From decfeceb211697b18b2525ec533a95ed03418e1d Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Sun, 4 Apr 2021 23:40:01 +0100 Subject: lzw: Direct output into frame data, avoiding stack. If the frame is non-interlaced, and has the same rowstride as the full image, then we can decode lzw directly into the output image. --- src/libnsgif.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 2 deletions(-) (limited to 'src/libnsgif.c') diff --git a/src/libnsgif.c b/src/libnsgif.c index 752f8c2..3c49218 100644 --- a/src/libnsgif.c +++ b/src/libnsgif.c @@ -626,8 +626,8 @@ static gif_result gif__recover_previous_frame(const gif_animation *gif) return GIF_OK; } -static inline gif_result -gif__decode(gif_animation *gif, +static gif_result +gif__decode_complex(gif_animation *gif, unsigned int frame, unsigned int width, unsigned int height, @@ -701,6 +701,85 @@ gif__decode(gif_animation *gif, return ret; } +static gif_result +gif__decode_simple(gif_animation *gif, + unsigned int frame, + unsigned int height, + unsigned int offset_y, + uint8_t minimum_code_size, + unsigned int *restrict frame_data, + unsigned int *restrict colour_table) +{ + unsigned int transparency_index; + uint32_t pixels = gif->width * height; + uint32_t written = 0; + 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); + if (res != LZW_OK) { + return gif_error_from_lzw(res); + } + + transparency_index = gif->frames[frame].transparency ? + gif->frames[frame].transparency_index : + GIF_NO_TRANSPARENCY; + + frame_data += (offset_y * gif->width); + + while (pixels > 0) { + res = lzw_decode_map_continuous(gif->lzw_ctx, + transparency_index, colour_table, + frame_data, pixels, &written); + pixels -= written; + frame_data += written; + 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; + } + } + + if (pixels == 0) { + ret = GIF_OK; + } + + return ret; +} + +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) +{ + gif_result ret; + + if (interlace == false && width == gif->width && offset_x == 0) { + ret = gif__decode_simple(gif, frame, height, offset_y, + minimum_code_size, frame_data, colour_table); + } else { + ret = gif__decode_complex(gif, frame, width, height, + offset_x, offset_y, interlace, + minimum_code_size, frame_data, colour_table); + } + + return ret; +} + /** * decode a gif frame * -- cgit v1.2.3