updale libnsgif from upstream

seems slightly slower overall
This commit is contained in:
John Cupitt 2021-10-07 10:48:12 +01:00
parent 1192d87acf
commit 60bae63644
4 changed files with 244 additions and 172 deletions

View File

@ -8,9 +8,9 @@ but within the libvips build system.
Run `./update.sh` to update this copy of libnsgif from the upstream repo. It Run `./update.sh` to update this copy of libnsgif from the upstream repo. It
will also patch libnsgif.c to prevent it modifying the input. will also patch libnsgif.c to prevent it modifying the input.
Last updated 28 Feb 2021. Last updated 7 Oct 2021.
# To do # To do
No attempt made to run tests or build docs. Though the gif loader is tested as No attempt made to run tests or build docs. Though the gif loader is tested
part of the libvips test suite. as part of the libvips test suite.

View File

@ -549,6 +549,8 @@ static gif_result gif_error_from_lzw(lzw_result l_res)
[LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR, [LZW_BAD_ICODE] = GIF_FRAME_DATA_ERROR,
[LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR, [LZW_BAD_CODE] = GIF_FRAME_DATA_ERROR,
}; };
assert(l_res != LZW_BAD_PARAM);
assert(l_res != LZW_NO_COLOUR);
return g_res[l_res]; return g_res[l_res];
} }
@ -638,9 +640,8 @@ gif__decode_complex(gif_animation *gif,
lzw_result res; lzw_result res;
/* Initialise the LZW decoding */ /* Initialise the LZW decoding */
res = lzw_decode_init(gif->lzw_ctx, gif->gif_data, res = lzw_decode_init(gif->lzw_ctx, minimum_code_size,
gif->buffer_size, gif->buffer_position, gif->gif_data, gif->buffer_size, gif->buffer_position);
minimum_code_size);
if (res != LZW_OK) { if (res != LZW_OK) {
return gif_error_from_lzw(res); return gif_error_from_lzw(res);
} }
@ -675,20 +676,28 @@ gif__decode_complex(gif_animation *gif,
} }
break; break;
} }
res = lzw_decode_continuous(gif->lzw_ctx, res = lzw_decode(gif->lzw_ctx,
&uncompressed, &available); &uncompressed, &available);
} }
row_available = x < available ? x : available; row_available = x < available ? x : available;
x -= row_available; x -= row_available;
available -= row_available; available -= row_available;
while (row_available-- > 0) { if (transparency_index > 0xFF) {
register unsigned int colour; while (row_available-- > 0) {
colour = *uncompressed++; *frame_scanline++ =
if (colour != transparency_index) { colour_table[*uncompressed++];
*frame_scanline = colour_table[colour]; }
} else {
while (row_available-- > 0) {
register unsigned int colour;
colour = *uncompressed++;
if (colour != transparency_index) {
*frame_scanline =
colour_table[colour];
}
frame_scanline++;
} }
frame_scanline++;
} }
} }
} }
@ -710,23 +719,22 @@ gif__decode_simple(gif_animation *gif,
gif_result ret = GIF_OK; gif_result ret = GIF_OK;
lzw_result res; 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 ? transparency_index = gif->frames[frame].transparency ?
gif->frames[frame].transparency_index : gif->frames[frame].transparency_index :
GIF_NO_TRANSPARENCY; GIF_NO_TRANSPARENCY;
/* Initialise the LZW decoding */
res = lzw_decode_init_map(gif->lzw_ctx,
minimum_code_size, transparency_index, colour_table,
gif->gif_data, gif->buffer_size, gif->buffer_position);
if (res != LZW_OK) {
return gif_error_from_lzw(res);
}
frame_data += (offset_y * gif->width); frame_data += (offset_y * gif->width);
while (pixels > 0) { while (pixels > 0) {
res = lzw_decode_map_continuous(gif->lzw_ctx, res = lzw_decode_map(gif->lzw_ctx,
transparency_index, colour_table,
frame_data, pixels, &written); frame_data, pixels, &written);
pixels -= written; pixels -= written;
frame_data += written; frame_data += written;

View File

@ -68,31 +68,32 @@ struct lzw_table_entry {
struct lzw_ctx { struct lzw_ctx {
struct lzw_read_ctx input; /**< Input reading context */ struct lzw_read_ctx input; /**< Input reading context */
uint32_t prev_code; /**< Code read from input previously. */ uint16_t prev_code; /**< Code read from input previously. */
uint32_t prev_code_first; /**< First value of previous code. */ uint16_t prev_code_first; /**< First value of previous code. */
uint32_t prev_code_count; /**< Total values for previous code. */ uint16_t prev_code_count; /**< Total values for previous code. */
uint32_t initial_code_size; /**< Starting LZW code size. */ uint8_t initial_code_size; /**< Starting LZW code size. */
uint32_t code_size; /**< Current LZW code size. */ uint8_t code_size; /**< Current LZW code size. */
uint32_t code_max; /**< Max code value for current code size. */ uint16_t code_max; /**< Max code value for current code size. */
uint32_t clear_code; /**< Special Clear code value */ uint16_t clear_code; /**< Special Clear code value */
uint32_t eoi_code; /**< Special End of Information code value */ uint16_t eoi_code; /**< Special End of Information code value */
uint32_t table_size; /**< Next position in table to fill. */ uint16_t table_size; /**< Next position in table to fill. */
uint32_t output_code; /**< Code that has been partially output. */ uint16_t output_code; /**< Code that has been partially output. */
uint32_t output_left; /**< Number of values left for output_code. */ uint16_t output_left; /**< Number of values left for output_code. */
uint32_t transparency_idx; /**< Index representing transparency. */ bool has_transparency; /**< Whether the image is opaque. */
uint32_t *restrict colour_map; /**< Index to pixel colour mapping */ uint8_t transparency_idx; /**< Index representing transparency. */
const uint32_t *restrict colour_map; /**< Index to colour mapping. */
/** Output value stack. */
uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
/** LZW code table. Generated during decode. */ /** LZW code table. Generated during decode. */
struct lzw_table_entry table[LZW_TABLE_ENTRY_MAX]; struct lzw_table_entry table[LZW_TABLE_ENTRY_MAX];
/** Output value stack. */
uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
}; };
@ -165,8 +166,8 @@ static lzw_result lzw__block_advance(struct lzw_read_ctx *restrict ctx)
*/ */
static inline lzw_result lzw__read_code( static inline lzw_result lzw__read_code(
struct lzw_read_ctx *restrict ctx, struct lzw_read_ctx *restrict ctx,
uint32_t code_size, uint16_t code_size,
uint32_t *restrict code_out) uint16_t *restrict code_out)
{ {
uint32_t code = 0; uint32_t code = 0;
uint32_t current_bit = ctx->sb_bit & 0x7; uint32_t current_bit = ctx->sb_bit & 0x7;
@ -232,9 +233,9 @@ static inline lzw_result lzw__read_code(
*/ */
static inline lzw_result lzw__handle_clear( static inline lzw_result lzw__handle_clear(
struct lzw_ctx *ctx, struct lzw_ctx *ctx,
uint32_t *code_out) uint16_t *code_out)
{ {
uint32_t code; uint16_t code;
/* Reset table building context */ /* Reset table building context */
ctx->code_size = ctx->initial_code_size; ctx->code_size = ctx->initial_code_size;
@ -259,27 +260,26 @@ static inline lzw_result lzw__handle_clear(
return LZW_OK; return LZW_OK;
} }
/* Exported function, documented in lzw.h */ /* Exported function, documented in lzw.h */
lzw_result lzw_decode_init( lzw_result lzw_decode_init(
struct lzw_ctx *ctx, struct lzw_ctx *ctx,
const uint8_t *compressed_data, uint8_t minimum_code_size,
uint32_t compressed_data_len, const uint8_t *input_data,
uint32_t compressed_data_pos, uint32_t input_length,
uint8_t minimum_code_size) uint32_t input_pos)
{ {
struct lzw_table_entry *table = ctx->table; struct lzw_table_entry *table = ctx->table;
lzw_result res; lzw_result res;
uint32_t code; uint16_t code;
if (minimum_code_size >= LZW_CODE_MAX) { if (minimum_code_size >= LZW_CODE_MAX) {
return LZW_BAD_ICODE; return LZW_BAD_ICODE;
} }
/* Initialise the input reading context */ /* Initialise the input reading context */
ctx->input.data = compressed_data; ctx->input.data = input_data;
ctx->input.data_len = compressed_data_len; ctx->input.data_len = input_length;
ctx->input.data_sb_next = compressed_data_pos; ctx->input.data_sb_next = input_pos;
ctx->input.sb_bit = 0; ctx->input.sb_bit = 0;
ctx->input.sb_bit_count = 0; ctx->input.sb_bit_count = 0;
@ -293,7 +293,7 @@ lzw_result lzw_decode_init(
ctx->output_left = 0; ctx->output_left = 0;
/* Initialise the standard table entries */ /* Initialise the standard table entries */
for (uint32_t i = 0; i < ctx->clear_code; ++i) { for (uint16_t i = 0; i < ctx->clear_code; i++) {
table[i].first = i; table[i].first = i;
table[i].value = i; table[i].value = i;
table[i].count = 1; table[i].count = 1;
@ -313,6 +313,39 @@ lzw_result lzw_decode_init(
ctx->output_code = code; ctx->output_code = code;
ctx->output_left = 1; ctx->output_left = 1;
ctx->has_transparency = false;
ctx->transparency_idx = 0;
ctx->colour_map = NULL;
return LZW_OK;
}
/* Exported function, documented in lzw.h */
lzw_result lzw_decode_init_map(
struct lzw_ctx *ctx,
uint8_t minimum_code_size,
uint32_t transparency_idx,
const uint32_t *colour_table,
const uint8_t *input_data,
uint32_t input_length,
uint32_t input_pos)
{
lzw_result res;
if (colour_table == NULL) {
return LZW_BAD_PARAM;
}
res = lzw_decode_init(ctx, minimum_code_size,
input_data, input_length, input_pos);
if (res != LZW_OK) {
return res;
}
ctx->has_transparency = (transparency_idx <= 0xFF);
ctx->transparency_idx = transparency_idx;
ctx->colour_map = colour_table;
return LZW_OK; return LZW_OK;
} }
@ -324,7 +357,7 @@ lzw_result lzw_decode_init(
*/ */
static inline void lzw__table_add_entry( static inline void lzw__table_add_entry(
struct lzw_ctx *ctx, struct lzw_ctx *ctx,
uint32_t code) uint16_t code)
{ {
struct lzw_table_entry *entry = &ctx->table[ctx->table_size]; struct lzw_table_entry *entry = &ctx->table[ctx->table_size];
@ -338,30 +371,31 @@ static inline void lzw__table_add_entry(
typedef uint32_t (*lzw_writer_fn)( typedef uint32_t (*lzw_writer_fn)(
struct lzw_ctx *ctx, struct lzw_ctx *ctx,
void *restrict output, void *restrict output_data,
uint32_t length, uint32_t output_length,
uint32_t used, uint32_t output_pos,
uint32_t code, uint16_t code,
uint32_t left); uint16_t left);
/** /**
* Get the next LZW code and write its value(s) to output buffer. * Get the next LZW code and write its value(s) to output buffer.
* *
* \param[in] ctx LZW reading context, updated. * \param[in] ctx LZW reading context, updated.
* \param[in] output Array to write output values into. * \param[in] write_fn Function for writing pixels to output.
* \param[in] length Size of output array. * \param[in] output_data Array to write output values into.
* \param[in] write_pixels Function for writing pixels to output. * \param[in] output_length Size of output array.
* \param[in,out] used Number of values written. Updated on exit. * \param[in,out] output_written Number of values written. Updated on exit.
* \return LZW_OK on success, or appropriate error code otherwise. * \return LZW_OK on success, or appropriate error code otherwise.
*/ */
static inline lzw_result lzw__decode(struct lzw_ctx *ctx, static inline lzw_result lzw__decode(
void *restrict output, struct lzw_ctx *ctx,
uint32_t length, lzw_writer_fn write_fn,
lzw_writer_fn write_pixels, void *restrict output_data,
uint32_t *restrict used) uint32_t output_length,
uint32_t *restrict output_written)
{ {
lzw_result res; lzw_result res;
uint32_t code; uint16_t code;
/* Get a new code from the input */ /* Get a new code from the input */
res = lzw__read_code(&ctx->input, ctx->code_size, &code); res = lzw__read_code(&ctx->input, ctx->code_size, &code);
@ -385,7 +419,7 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
} }
} else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) { } else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
uint32_t size = ctx->table_size; uint16_t size = ctx->table_size;
lzw__table_add_entry(ctx, (code < size) ? lzw__table_add_entry(ctx, (code < size) ?
ctx->table[code].first : ctx->table[code].first :
ctx->prev_code_first); ctx->prev_code_first);
@ -397,8 +431,9 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
} }
} }
*used += write_pixels(ctx, output, length, *used, code, *output_written += write_fn(ctx,
ctx->table[code].count); output_data, output_length, *output_written,
code, ctx->table[code].count);
/* Store details of this code as "previous code" to the context. */ /* Store details of this code as "previous code" to the context. */
ctx->prev_code_first = ctx->table[code].first; ctx->prev_code_first = ctx->table[code].first;
@ -416,25 +451,25 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
* this call, then there is more data for this code left to output. The code * this call, then there is more data for this code left to output. The code
* is stored to the context as `ctx->output_code`. * is stored to the context as `ctx->output_code`.
* *
* \param[in] ctx LZW reading context, updated. * \param[in] ctx LZW reading context, updated.
* \param[in] output Array to write output values into. * \param[in] output_data Array to write output values into.
* \param[in] length Size of output array. * \param[in] output_length length Size of output array.
* \param[in] used Current position in output array. * \param[in] output_used Current position in output array.
* \param[in] code LZW code to output values for. * \param[in] code LZW code to output values for.
* \param[in] left Number of values remaining to output for this value. * \param[in] left Number of values remaining to output for this code.
* \return Number of pixel values written. * \return Number of pixel values written.
*/ */
static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx, static inline uint32_t lzw__write_fn(struct lzw_ctx *ctx,
void *restrict output, void *restrict output_data,
uint32_t length, uint32_t output_length,
uint32_t used, uint32_t output_used,
uint32_t code, uint16_t code,
uint32_t left) uint16_t left)
{ {
uint8_t *restrict output_pos = (uint8_t *)output + used; uint8_t *restrict output_pos = (uint8_t *)output_data + output_used;
const struct lzw_table_entry * const table = ctx->table; const struct lzw_table_entry * const table = ctx->table;
uint32_t space = length - used; uint32_t space = output_length - output_used;
uint32_t count = left; uint16_t count = left;
if (count > space) { if (count > space) {
left = count - space; left = count - space;
@ -463,23 +498,24 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
} }
/* Exported function, documented in lzw.h */ /* Exported function, documented in lzw.h */
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx, lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t *restrict *const restrict data, const uint8_t *restrict *const restrict output_data,
uint32_t *restrict used) uint32_t *restrict output_written)
{ {
*used = 0; const uint32_t output_length = sizeof(ctx->stack_base);
*data = ctx->stack_base;
*output_written = 0;
*output_data = ctx->stack_base;
if (ctx->output_left != 0) { if (ctx->output_left != 0) {
*used += lzw__write_pixels(ctx, *output_written += lzw__write_fn(ctx,
ctx->stack_base, sizeof(ctx->stack_base), *used, ctx->stack_base, output_length, *output_written,
ctx->output_code, ctx->output_left); ctx->output_code, ctx->output_left);
} }
while (*used != sizeof(ctx->stack_base)) { while (*output_written != output_length) {
lzw_result res = lzw__decode(ctx, lzw_result res = lzw__decode(ctx, lzw__write_fn,
ctx->stack_base, sizeof(ctx->stack_base), ctx->stack_base, output_length, output_written);
lzw__write_pixels, used);
if (res != LZW_OK) { if (res != LZW_OK) {
return res; return res;
} }
@ -489,32 +525,32 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
} }
/** /**
* Write colour mapped values for this code to the output stack. * Write colour mapped values for this code to the output.
* *
* If there isn't enough space in the output stack, this function will write * If there isn't enough space in the output stack, this function will write
* the as many as it can into the output. If `ctx->output_left > 0` after * the as many as it can into the output. If `ctx->output_left > 0` after
* this call, then there is more data for this code left to output. The code * this call, then there is more data for this code left to output. The code
* is stored to the context as `ctx->output_code`. * is stored to the context as `ctx->output_code`.
* *
* \param[in] ctx LZW reading context, updated. * \param[in] ctx LZW reading context, updated.
* \param[in] output Array to write output values into. * \param[in] output_data Array to write output values into.
* \param[in] length Size of output array. * \param[in] output_length Size of output array.
* \param[in] used Current position in output array. * \param[in] output_used Current position in output array.
* \param[in] code LZW code to output values for. * \param[in] code LZW code to output values for.
* \param[in] left Number of values remaining to output for this value. * \param[in] left Number of values remaining to output for code.
* \return Number of pixel values written. * \return Number of pixel values written.
*/ */
static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx, static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx,
void *restrict buffer, void *restrict output_data,
uint32_t length, uint32_t output_length,
uint32_t used, uint32_t output_used,
uint32_t code, uint16_t code,
uint32_t left) uint16_t left)
{ {
uint32_t *restrict stack_pos = (uint32_t *)buffer + used; uint32_t *restrict output_pos = (uint32_t *)output_data + output_used;
const struct lzw_table_entry * const table = ctx->table; const struct lzw_table_entry * const table = ctx->table;
uint32_t space = length - used; uint32_t space = output_length - output_used;
uint32_t count = left; uint16_t count = left;
if (count > space) { if (count > space) {
left = count - space; left = count - space;
@ -531,40 +567,48 @@ static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
code = entry->extends; code = entry->extends;
} }
stack_pos += count; output_pos += count;
for (unsigned i = count; i != 0; i--) { if (ctx->has_transparency) {
const struct lzw_table_entry *entry = table + code; for (unsigned i = count; i != 0; i--) {
--stack_pos; const struct lzw_table_entry *entry = table + code;
if (entry->value != ctx->transparency_idx) { --output_pos;
*stack_pos = ctx->colour_map[entry->value]; if (entry->value != ctx->transparency_idx) {
*output_pos = ctx->colour_map[entry->value];
}
code = entry->extends;
}
} else {
for (unsigned i = count; i != 0; i--) {
const struct lzw_table_entry *entry = table + code;
*--output_pos = ctx->colour_map[entry->value];
code = entry->extends;
} }
code = entry->extends;
} }
return count; return count;
} }
/* Exported function, documented in lzw.h */ /* Exported function, documented in lzw.h */
lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx, lzw_result lzw_decode_map(struct lzw_ctx *ctx,
uint32_t transparency_idx, uint32_t *restrict output_data,
uint32_t *restrict colour_map, uint32_t output_length,
uint32_t *restrict data, uint32_t *restrict output_written)
uint32_t length,
uint32_t *restrict used)
{ {
*used = 0; *output_written = 0;
ctx->transparency_idx = transparency_idx; if (ctx->colour_map == NULL) {
ctx->colour_map = colour_map; return LZW_NO_COLOUR;
}
if (ctx->output_left != 0) { if (ctx->output_left != 0) {
*used += lzw__write_pixels_map(ctx, data, length, *used, *output_written += lzw__map_write_fn(ctx,
output_data, output_length, *output_written,
ctx->output_code, ctx->output_left); ctx->output_code, ctx->output_left);
} }
while (*used != sizeof(ctx->stack_base)) { while (*output_written != output_length) {
lzw_result res = lzw__decode(ctx, data, length, lzw_result res = lzw__decode(ctx, lzw__map_write_fn,
lzw__write_pixels_map, used); output_data, output_length, output_written);
if (res != LZW_OK) { if (res != LZW_OK) {
return res; return res;
} }

View File

@ -16,7 +16,6 @@
* Decoder for GIF LZW data. * Decoder for GIF LZW data.
*/ */
/** Maximum LZW code size in bits */ /** Maximum LZW code size in bits */
#define LZW_CODE_MAX 12 #define LZW_CODE_MAX 12
@ -32,7 +31,9 @@ typedef enum lzw_result {
LZW_NO_MEM, /**< Error: Out of memory */ LZW_NO_MEM, /**< Error: Out of memory */
LZW_NO_DATA, /**< Error: Out of data */ LZW_NO_DATA, /**< Error: Out of data */
LZW_EOI_CODE, /**< Error: End of Information code */ LZW_EOI_CODE, /**< Error: End of Information code */
LZW_NO_COLOUR, /**< Error: No colour map provided. */
LZW_BAD_ICODE, /**< Error: Bad initial LZW code */ LZW_BAD_ICODE, /**< Error: Bad initial LZW code */
LZW_BAD_PARAM, /**< Error: Bad function parameter. */
LZW_BAD_CODE, /**< Error: Bad LZW code */ LZW_BAD_CODE, /**< Error: Bad LZW code */
} lzw_result; } lzw_result;
@ -58,62 +59,81 @@ void lzw_context_destroy(
/** /**
* Initialise an LZW decompression context for decoding. * Initialise an LZW decompression context for decoding.
* *
* Caller owns neither `stack_base_out` or `stack_pos_out`. * \param[in] ctx The LZW decompression context to initialise.
* * \param[in] minimum_code_size The LZW Minimum Code Size.
* \param[in] ctx The LZW decompression context to initialise. * \param[in] input_data The compressed data.
* \param[in] compressed_data The compressed data. * \param[in] input_length Byte length of compressed data.
* \param[in] compressed_data_len Byte length of compressed data. * \param[in] input_pos Start position in data. Must be position
* \param[in] compressed_data_pos Start position in data. Must be position * of a size byte at sub-block start.
* of a size byte at sub-block start.
* \param[in] minimum_code_size The LZW Minimum Code Size.
* \param[out] stack_base_out Returns base of decompressed data stack.
* \return LZW_OK on success, or appropriate error code otherwise. * \return LZW_OK on success, or appropriate error code otherwise.
*/ */
lzw_result lzw_decode_init( lzw_result lzw_decode_init(
struct lzw_ctx *ctx, struct lzw_ctx *ctx,
const uint8_t *compressed_data, uint8_t minimum_code_size,
uint32_t compressed_data_len, const uint8_t *input_data,
uint32_t compressed_data_pos, uint32_t input_length,
uint8_t minimum_code_size); uint32_t input_pos);
/** /**
* Read input codes until end of lzw context owned output buffer. * Read input codes until end of LZW context owned output buffer.
* *
* Ensure anything in output is used before calling this, as anything * Ensure anything in output is used before calling this, as anything
* on the there before this call will be trampled. * there before this call will be trampled.
* *
* \param[in] ctx LZW reading context, updated. * \param[in] ctx LZW reading context, updated.
* \param[out] data Returns pointer to array of output values. * \param[out] output_data Returns pointer to array of output values.
* \param[out] used Returns the number of values written to data. * \param[out] output_written Returns the number of values written to data.
* \return LZW_OK on success, or appropriate error code otherwise. * \return LZW_OK on success, or appropriate error code otherwise.
*/ */
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx, lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t *restrict *const restrict data, const uint8_t *restrict *const restrict output_data,
uint32_t *restrict used); uint32_t *restrict output_written);
/** /**
* Read LZW codes into client buffer, mapping output to colours. * Initialise an LZW decompression context for decoding to colour map values.
*
* Ensure anything in output is used before calling this, as anything
* on the there before this call will be trampled.
* *
* For transparency to work correctly, the given client buffer must have * For transparency to work correctly, the given client buffer must have
* the values from the previous frame. The transparency_idx should be a value * the values from the previous frame. The transparency_idx should be a value
* of 256 or above, if the frame does not have transparency. * of 256 or above, if the frame does not have transparency.
* *
* \param[in] ctx LZW reading context, updated. * \param[in] ctx The LZW decompression context to initialise.
* \param[in] transparency_idx Index representing transparency. * \param[in] minimum_code_size The LZW Minimum Code Size.
* \param[in] colour_map Index to pixel colour mapping * \param[in] transparency_idx Index representing transparency.
* \param[in] data Client buffer to fill with colour mapped values. * \param[in] colour_table Index to pixel colour mapping.
* \param[in] length Size of output array. * \param[in] input_data The compressed data.
* \param[out] used Returns the number of values written to data. * \param[in] input_length Byte length of compressed data.
* \param[in] input_pos Start position in data. Must be position
* of a size byte at sub-block start.
* \return LZW_OK on success, or appropriate error code otherwise. * \return LZW_OK on success, or appropriate error code otherwise.
*/ */
lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx, lzw_result lzw_decode_init_map(
struct lzw_ctx *ctx,
uint8_t minimum_code_size,
uint32_t transparency_idx, uint32_t transparency_idx,
uint32_t *restrict colour_table, const uint32_t *colour_table,
uint32_t *restrict data, const uint8_t *input_data,
uint32_t length, uint32_t input_length,
uint32_t *restrict used); uint32_t input_pos);
/**
* Read LZW codes into client buffer, mapping output to colours.
*
* The context must have been initialised using \ref lzw_decode_init_map
* before calling this function, in order to provide the colour mapping table
* and any transparency index.
*
* Ensure anything in output is used before calling this, as anything
* there before this call will be trampled.
*
* \param[in] ctx LZW reading context, updated.
* \param[in] output_data Client buffer to fill with colour mapped values.
* \param[in] output_length Size of output array.
* \param[out] output_written Returns the number of values written to data.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_map(struct lzw_ctx *ctx,
uint32_t *restrict output_data,
uint32_t output_length,
uint32_t *restrict output_written);
#endif #endif