gif: Split out gif frame data decode.
This commit is contained in:
parent
c9a639d2bd
commit
8d8aa0dd46
@ -618,6 +618,83 @@ static gif_result gif__recover_previous_frame(const gif_animation *gif)
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
static inline gif_result
|
||||
gif__decode(gif_animation *gif,
|
||||
unsigned int frame,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int offset_x,
|
||||
unsigned int offset_y,
|
||||
unsigned int interlace,
|
||||
uint8_t minimum_code_size,
|
||||
unsigned int *restrict frame_data,
|
||||
unsigned int *restrict colour_table)
|
||||
{
|
||||
const uint8_t *stack_base;
|
||||
const uint8_t *stack_pos;
|
||||
gif_result ret = GIF_OK;
|
||||
lzw_result res;
|
||||
|
||||
/* Initialise the LZW decoding */
|
||||
res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
|
||||
gif->buffer_size, gif->buffer_position,
|
||||
minimum_code_size, &stack_base, &stack_pos);
|
||||
if (res != LZW_OK) {
|
||||
return gif_error_from_lzw(res);
|
||||
}
|
||||
|
||||
for (unsigned int y = 0; y < height; y++) {
|
||||
unsigned int x;
|
||||
unsigned int decode_y;
|
||||
unsigned int *frame_scanline;
|
||||
|
||||
if (interlace) {
|
||||
decode_y = gif_interlaced_line(height, y) + offset_y;
|
||||
} else {
|
||||
decode_y = y + offset_y;
|
||||
}
|
||||
frame_scanline = frame_data + offset_x + (decode_y * gif->width);
|
||||
|
||||
/* Rather than decoding pixel by pixel, we try to burst
|
||||
* out streams of data to remove the need for end-of
|
||||
* data checks every pixel.
|
||||
*/
|
||||
x = width;
|
||||
while (x > 0) {
|
||||
unsigned int burst_bytes = (stack_pos - stack_base);
|
||||
if (burst_bytes > 0) {
|
||||
if (burst_bytes > x) {
|
||||
burst_bytes = x;
|
||||
}
|
||||
x -= burst_bytes;
|
||||
while (burst_bytes-- > 0) {
|
||||
register unsigned char colour;
|
||||
colour = *--stack_pos;
|
||||
if (((gif->frames[frame].transparency) &&
|
||||
(colour != gif->frames[frame].transparency_index)) ||
|
||||
(!gif->frames[frame].transparency)) {
|
||||
*frame_scanline = colour_table[colour];
|
||||
}
|
||||
frame_scanline++;
|
||||
}
|
||||
} else {
|
||||
res = lzw_decode(gif->lzw_ctx, &stack_pos);
|
||||
if (res != LZW_OK) {
|
||||
/* Unexpected end of frame, try to recover */
|
||||
if (res == LZW_OK_EOD) {
|
||||
ret = GIF_OK;
|
||||
} else {
|
||||
ret = gif_error_from_lzw(res);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode a gif frame
|
||||
*
|
||||
@ -638,11 +715,8 @@ gif_internal_decode_frame(gif_animation *gif,
|
||||
unsigned int flags, colour_table_size, interlace;
|
||||
unsigned int *colour_table;
|
||||
unsigned int *frame_data = 0; // Set to 0 for no warnings
|
||||
unsigned int *frame_scanline;
|
||||
unsigned int save_buffer_position;
|
||||
unsigned int return_value = 0;
|
||||
unsigned int x, y, decode_y, burst_bytes;
|
||||
register unsigned char colour;
|
||||
|
||||
/* Ensure this frame is supposed to be decoded */
|
||||
if (gif->frames[frame].display == false) {
|
||||
@ -796,10 +870,6 @@ gif_internal_decode_frame(gif_animation *gif,
|
||||
|
||||
/* If we are clearing the image we just clear, if not decode */
|
||||
if (!clear_image) {
|
||||
lzw_result res;
|
||||
const uint8_t *stack_base;
|
||||
const uint8_t *stack_pos;
|
||||
|
||||
/* Ensure we have enough data for a 1-byte LZW code size +
|
||||
* 1-byte gif trailer
|
||||
*/
|
||||
@ -863,62 +933,15 @@ gif_internal_decode_frame(gif_animation *gif,
|
||||
gif->decoded_frame = frame;
|
||||
gif->buffer_position = (gif_data - gif->gif_data) + 1;
|
||||
|
||||
/* Initialise the LZW decoding */
|
||||
res = lzw_decode_init(gif->lzw_ctx, gif->gif_data,
|
||||
gif->buffer_size, gif->buffer_position,
|
||||
gif_data[0], &stack_base, &stack_pos);
|
||||
if (res != LZW_OK) {
|
||||
return gif_error_from_lzw(res);
|
||||
}
|
||||
|
||||
/* Decompress the data */
|
||||
for (y = 0; y < height; y++) {
|
||||
if (interlace) {
|
||||
decode_y = gif_interlaced_line(height, y) + offset_y;
|
||||
} else {
|
||||
decode_y = y + offset_y;
|
||||
}
|
||||
frame_scanline = frame_data + offset_x + (decode_y * gif->width);
|
||||
|
||||
/* Rather than decoding pixel by pixel, we try to burst
|
||||
* out streams of data to remove the need for end-of
|
||||
* data checks every pixel.
|
||||
*/
|
||||
x = width;
|
||||
while (x > 0) {
|
||||
burst_bytes = (stack_pos - stack_base);
|
||||
if (burst_bytes > 0) {
|
||||
if (burst_bytes > x) {
|
||||
burst_bytes = x;
|
||||
}
|
||||
x -= burst_bytes;
|
||||
while (burst_bytes-- > 0) {
|
||||
colour = *--stack_pos;
|
||||
if (((gif->frames[frame].transparency) &&
|
||||
(colour != gif->frames[frame].transparency_index)) ||
|
||||
(!gif->frames[frame].transparency)) {
|
||||
*frame_scanline = colour_table[colour];
|
||||
}
|
||||
frame_scanline++;
|
||||
}
|
||||
} else {
|
||||
res = lzw_decode(gif->lzw_ctx, &stack_pos);
|
||||
if (res != LZW_OK) {
|
||||
/* Unexpected end of frame, try to recover */
|
||||
if (res == LZW_OK_EOD) {
|
||||
return_value = GIF_OK;
|
||||
} else {
|
||||
return_value = gif_error_from_lzw(res);
|
||||
}
|
||||
goto gif_decode_frame_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return_value = gif__decode(gif, frame, width, height,
|
||||
offset_x, offset_y, interlace, gif_data[0],
|
||||
frame_data, colour_table);
|
||||
} else {
|
||||
/* Clear our frame */
|
||||
if (gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) {
|
||||
unsigned int y;
|
||||
for (y = 0; y < height; y++) {
|
||||
unsigned int *frame_scanline;
|
||||
frame_scanline = frame_data + offset_x + ((offset_y + y) * gif->width);
|
||||
if (gif->frames[frame].transparency) {
|
||||
memset(frame_scanline,
|
||||
|
Loading…
Reference in New Issue
Block a user