Gitweb links:
...log
http://git.netsurf-browser.org/libnsgif.git/shortlog/4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5
...commit
http://git.netsurf-browser.org/libnsgif.git/commit/4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5
...tree
http://git.netsurf-browser.org/libnsgif.git/tree/4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5
The branch, tlsa/lzw-optimise has been updated
discards ffa65b20ef33d6323cb073dc119bcd3d1ca12c5e (commit)
discards 18a3f45e896ee30d817b9ddfe4dce3bf2ee6bba0 (commit)
discards 1e284b45744009ba77e6b44709960fdb1592cdbb (commit)
discards 98ca2136c67ea6a7a9d0f57b6481288fe9f54f64 (commit)
discards 5454d9e6be9db8be8f759ec74e37558b93d85bc1 (commit)
discards ad9ddb59c4f0607821e52919a5ffdd09a1090a4e (commit)
discards 19bbdfd0e2cea3d133d3de1d275496060d069376 (commit)
discards a37a58757033a143ca6055ddf57111f5bdc6afec (commit)
discards 7aa7e7cbf5815d833bac688990e9e4d48226a83b (commit)
discards 92850849f8cefe78c6abad56623f7ee2941fc340 (commit)
discards 80d152f7e3a67b65302a467ad1c7dd5c03ff3b29 (commit)
discards 0ecaf6688dfcfb9a36824df9b13fa75ce02e554d (commit)
discards 680babcd5768289ae72434c5d89c351a505a2136 (commit)
discards 01faec4a877bba33a7fe1ad8db8d91288548c1a0 (commit)
discards d59e5eb2ec7db3009c6a7054c84dcae9273038c5 (commit)
discards e708ae66a41c5f5eccc043bcf02bd0dccb132403 (commit)
discards e6c790fc877a231653f92b70c75a456812b5be0d (commit)
discards 0d7049e414806b8af7f835cae9321138d4042a73 (commit)
discards 970cc6c57b6d245ef20988b777edda51b3325184 (commit)
discards aa6d16b88dc74f66e7a4f2041886f57ce750237e (commit)
via 4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5 (commit)
via 8f4a3af5e6322c9deb2aa6e1b04952c4031f33b2 (commit)
via 34d6277cf14fa104de5216fe156beab37d010d94 (commit)
via 28ee35e73ef56eefbe6992034a2b8046d343393b (commit)
via b33ddeb9591c34e12f6d9428bc25b58d2edfbb7f (commit)
via d60461e06b690ef4583d767fd7d5c99415622e98 (commit)
via ec5b110f5af6618dd250c13e6fed0abd8040e813 (commit)
via 35079ae6fe202806f616cbbde19a5ff1aa964dc3 (commit)
via 412a5acea5762690dcf22498530165a7221532e0 (commit)
via 73f6376fc3ffbed45576a12f69675e09c2b02d1f (commit)
via a7183f1ea70b3f3c722b27f97c5d494ada1be231 (commit)
via 71a32374233598177e06ba9ee6214b9379bd40ba (commit)
via 9520f18f7290ba4a9080be62ac9d2dbc957866a8 (commit)
via cf304dc469bfe688f8ae70c6102803095edfd0df (commit)
via 62a814e980ea22b289b92b967cc0be7f373029ca (commit)
via 728be940120d8c63b7c44df45e0203671158116b (commit)
via ce2543b41e3394c5cf3161d49f1561ba34f674a2 (commit)
via 55c00227e1ad7cd7e03cc377fdaf052d57a56a06 (commit)
via 86786f4cc6800fa6c6282f8a87e2defacebeb94d (commit)
via d8e8d3cceef907f798276014ebdfed7c370fb866 (commit)
via bba28df0cc0c75338a63645c6a55aebfebe91c74 (commit)
via c817c6f1e48ffe98bf65d381f8b11cd4f82c83c6 (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (ffa65b20ef33d6323cb073dc119bcd3d1ca12c5e)
\
N -- N -- N (4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5
commit 4a91b95aaa8193b71e6a4c9347e6d5df7c551ec5
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
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.
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
*
diff --git a/src/lzw.c b/src/lzw.c
index bd16aa1..a57e125 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -85,6 +85,9 @@ struct lzw_ctx {
uint32_t output_code; /**< Code that has been partially output. */
uint32_t output_left; /**< Number of values left for output_code. */
+ uint32_t transparency_idx; /**< Index representing transparency. */
+ uint32_t *restrict colour_map; /**< Index to pixel colour mapping */
+
/** Output value stack. */
uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
@@ -363,6 +366,63 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx
*ctx,
return count;
}
+
+/**
+ * Write colour mapped values for this code to the output stack.
+ *
+ * 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
+ * this call, then there is more data for this code left to output. The code
+ * is stored to the context as `ctx->output_code`.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[in] length Size of output array.
+ * \param[in] used Current position in output array.
+ * \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for this value.
+ * \return Number of pixel values written.
+ */
+static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
+ void *restrict buffer,
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left)
+{
+ uint32_t *restrict stack_pos = (uint32_t *)buffer + used;
+ struct lzw_table_entry * const table = ctx->table;
+ uint32_t space = length - used;
+ uint32_t count = left;
+
+ if (count > space) {
+ left = count - space;
+ count = space;
+ } else {
+ left = 0;
+ }
+
+ ctx->output_code = code;
+ ctx->output_left = left;
+
+ for (unsigned i = left; i != 0; i--) {
+ struct lzw_table_entry *entry = table + code;
+ code = entry->extends;
+ }
+
+ stack_pos += count;
+ for (unsigned i = count; i != 0; i--) {
+ struct lzw_table_entry *entry = table + code;
+ --stack_pos;
+ if (entry->value != ctx->transparency_idx) {
+ *stack_pos = ctx->colour_map[entry->value];
+ }
+ code = entry->extends;
+ }
+
+ return count;
+}
+
/**
* Get the next LZW code and write its value(s) to output buffer.
*
@@ -374,7 +434,7 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx
*ctx,
* \return LZW_OK on success, or appropriate error code otherwise.
*/
static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
- uint8_t *restrict output,
+ void *restrict output,
uint32_t length,
lzw_writer_fn write_pixels,
uint32_t *restrict used)
@@ -463,3 +523,32 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
return LZW_OK;
}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+ uint32_t transparency_idx,
+ uint32_t *restrict colour_map,
+ uint32_t *restrict data,
+ uint32_t length,
+ uint32_t *restrict used)
+{
+ *used = 0;
+
+ ctx->transparency_idx = transparency_idx;
+ ctx->colour_map = colour_map;
+
+ if (ctx->output_left != 0) {
+ *used += lzw__write_pixels_map(ctx, data, length, *used,
+ ctx->output_code, ctx->output_left);
+ }
+
+ while (*used != sizeof(ctx->stack_base)) {
+ lzw_result res = lzw__decode(ctx, data, length,
+ lzw__write_pixels_map, used);
+ if (res != LZW_OK) {
+ return res;
+ }
+ }
+
+ return LZW_OK;
+}
diff --git a/src/lzw.h b/src/lzw.h
index c130c24..3be97d0 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -106,4 +106,29 @@ lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
const uint8_t ** const data,
uint32_t *used);
+/**
+ * Read LZW codes into client buffer, mapping output to colours.
+ *
+ * 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
+ * the values from the previous frame. The transparency_idx should be a value
+ * of 256 or above, if the frame does not have transparency.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] transparency_idx Index representing transparency.
+ * \param[in] colour_map Index to pixel colour mapping
+ * \param[in] data Client buffer to fill with colour mapped
values.
+ * \param[in] length Size of output array.
+ * \param[out] used Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
+ uint32_t transparency_idx,
+ uint32_t *restrict colour_table,
+ uint32_t *restrict data,
+ uint32_t length,
+ uint32_t *restrict used);
+
#endif
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=8f4a3af5e6322c9deb2aa6e1b04952c4031f33b2
commit 8f4a3af5e6322c9deb2aa6e1b04952c4031f33b2
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
gif: Handle any uncompressed output before exiting due to error.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index e0d97c0..752f8c2 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -672,8 +672,6 @@ gif__decode(gif_animation *gif,
const uint8_t *uncompressed;
unsigned row_available;
if (available == 0) {
- res = lzw_decode(gif->lzw_ctx,
- &uncompressed, &available);
if (res != LZW_OK) {
/* Unexpected end of frame, try to
recover */
if (res == LZW_OK_EOD) {
@@ -683,6 +681,8 @@ gif__decode(gif_animation *gif,
}
break;
}
+ res = lzw_decode(gif->lzw_ctx,
+ &uncompressed, &available);
}
row_available = x < available ? x : available;
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=34d6277cf14fa104de5216fe156beab37d010d94
commit 34d6277cf14fa104de5216fe156beab37d010d94
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Add function for decoding multiple LZW codes at a time.
diff --git a/src/lzw.c b/src/lzw.c
index 6ac4d49..bd16aa1 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -437,3 +437,29 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
lzw__write_pixels, used);
}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
+ const uint8_t ** const data,
+ uint32_t *used)
+{
+ *used = 0;
+ *data = ctx->stack_base;
+
+ if (ctx->output_left != 0) {
+ *used += lzw__write_pixels(ctx,
+ ctx->stack_base, sizeof(ctx->stack_base), *used,
+ ctx->output_code, ctx->output_left);
+ }
+
+ while (*used != sizeof(ctx->stack_base)) {
+ lzw_result res = lzw__decode(ctx,
+ ctx->stack_base, sizeof(ctx->stack_base),
+ lzw__write_pixels, used);
+ if (res != LZW_OK) {
+ return res;
+ }
+ }
+
+ return LZW_OK;
+}
diff --git a/src/lzw.h b/src/lzw.h
index dd0191e..c130c24 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -91,4 +91,19 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t *restrict *const restrict data,
uint32_t *restrict used);
+/**
+ * Read input codes until end of lzw context owned output buffer.
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * on the there before this call will be trampled.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] data Returns pointer to array of output values.
+ * \param[out] used Returns the number of values written to data.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
+ const uint8_t ** const data,
+ uint32_t *used);
+
#endif
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=28ee35e73ef56eefbe6992034a2b8046d343393b
commit 28ee35e73ef56eefbe6992034a2b8046d343393b
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Add support for resumable output of a single code.
This allows handling of insufficient output buffer space.
diff --git a/src/lzw.c b/src/lzw.c
index 24f4651..6ac4d49 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -82,6 +82,9 @@ struct lzw_ctx {
uint32_t table_size; /**< Next position in table to fill. */
+ uint32_t output_code; /**< Code that has been partially output. */
+ uint32_t output_left; /**< Number of values left for output_code. */
+
/** Output value stack. */
uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
@@ -263,6 +266,8 @@ lzw_result lzw_decode_init(
ctx->clear_code = (1 << minimum_code_size) + 0;
ctx->eoi_code = (1 << minimum_code_size) + 1;
+ ctx->output_left = 0;
+
/* Initialise the standard table entries */
for (uint32_t i = 0; i < ctx->clear_code; ++i) {
table[i].first = i;
@@ -296,21 +301,57 @@ static inline void lzw__table_add_entry(
ctx->table_size++;
}
+typedef uint32_t (*lzw_writer_fn)(
+ struct lzw_ctx *ctx,
+ void *restrict output,
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left);
+
/**
* Write values for this code to the output stack.
*
+ * 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
+ * this call, then there is more data for this code left to output. The code
+ * is stored to the context as `ctx->output_code`.
+ *
* \param[in] ctx LZW reading context, updated.
* \param[in] output Array to write output values into.
+ * \param[in] length Size of output array.
+ * \param[in] used Current position in output array.
* \param[in] code LZW code to output values for.
+ * \param[in] left Number of values remaining to output for this value.
* \return Number of pixel values written.
*/
static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
void *restrict output,
- uint32_t code)
+ uint32_t length,
+ uint32_t used,
+ uint32_t code,
+ uint32_t left)
{
- uint8_t *restrict output_pos = (uint8_t *)output;
+ uint8_t *restrict output_pos = (uint8_t *)output + used;
struct lzw_table_entry * const table = ctx->table;
- uint32_t count = table[code].count;
+ uint32_t space = length - used;
+ uint32_t count = left;
+
+ if (count > space) {
+ left = count - space;
+ count = space;
+ } else {
+ left = 0;
+ }
+
+ ctx->output_code = code;
+ ctx->output_left = left;
+
+ /* Skip over any values we don't have space for. */
+ for (unsigned i = left; i != 0; i--) {
+ struct lzw_table_entry *entry = table + code;
+ code = entry->extends;
+ }
output_pos += count;
for (unsigned i = count; i != 0; i--) {
@@ -323,20 +364,19 @@ static inline uint32_t lzw__write_pixels(struct lzw_ctx
*ctx,
}
/**
- * Fill the LZW stack with decompressed data
- *
- * Ensure anything in output is used before calling this, as anything
- * on the there before this call will be trampled.
+ * Get the next LZW code and write its value(s) to output buffer.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] output Array to write output values into.
- * \param[out] used Returns the number of values written.
- * Use with `stack_base_out` value from previous
- * lzw_decode_init() call.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[in] length Size of output array.
+ * \param[in] write_pixels Function for writing pixels to output.
+ * \param[in,out] used Number of values written. Updated on exit.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
uint8_t *restrict output,
+ uint32_t length,
+ lzw_writer_fn write_pixels,
uint32_t *restrict used)
{
lzw_result res;
@@ -375,7 +415,8 @@ static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
}
}
- *used += lzw__write_pixels(ctx, output, code);
+ *used += write_pixels(ctx, output, length, *used, code,
+ ctx->table[code].count);
}
/* Store details of this code as "previous code" to the context. */
@@ -393,5 +434,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
{
*used = 0;
*data = ctx->stack_base;
- return lzw__decode(ctx, ctx->stack_base, used);
+ return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
+ lzw__write_pixels, used);
}
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=b33ddeb9591c34e12f6d9428bc25b58d2edfbb7f
commit b33ddeb9591c34e12f6d9428bc25b58d2edfbb7f
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Return output array from decode function instead of init.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 1540e1d..e0d97c0 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -639,8 +639,6 @@ gif__decode(gif_animation *gif,
unsigned int *restrict colour_table)
{
unsigned int transparency_index;
- const uint8_t *stack_base;
- const uint8_t *stack_pos;
uint32_t available = 0;
gif_result ret = GIF_OK;
lzw_result res;
@@ -648,7 +646,7 @@ gif__decode(gif_animation *gif,
/* 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);
+ minimum_code_size);
if (res != LZW_OK) {
return gif_error_from_lzw(res);
}
@@ -657,7 +655,6 @@ gif__decode(gif_animation *gif,
gif->frames[frame].transparency_index :
GIF_NO_TRANSPARENCY;
- stack_pos = stack_base;
for (unsigned int y = 0; y < height; y++) {
unsigned int x;
unsigned int decode_y;
@@ -672,9 +669,11 @@ gif__decode(gif_animation *gif,
x = width;
while (x > 0) {
+ const uint8_t *uncompressed;
unsigned row_available;
if (available == 0) {
- res = lzw_decode(gif->lzw_ctx, &available);
+ res = lzw_decode(gif->lzw_ctx,
+ &uncompressed, &available);
if (res != LZW_OK) {
/* Unexpected end of frame, try to
recover */
if (res == LZW_OK_EOD) {
@@ -684,7 +683,6 @@ gif__decode(gif_animation *gif,
}
break;
}
- stack_pos = stack_base;
}
row_available = x < available ? x : available;
@@ -692,7 +690,7 @@ gif__decode(gif_animation *gif,
available -= row_available;
while (row_available-- > 0) {
register unsigned int colour;
- colour = *stack_pos++;
+ colour = *uncompressed++;
if (colour != transparency_index) {
*frame_scanline = colour_table[colour];
}
diff --git a/src/lzw.c b/src/lzw.c
index d3e0dcf..24f4651 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -241,8 +241,7 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
- uint8_t minimum_code_size,
- const uint8_t ** const stack_base_out)
+ uint8_t minimum_code_size)
{
struct lzw_table_entry *table = ctx->table;
@@ -274,7 +273,6 @@ lzw_result lzw_decode_init(
lzw__clear_table(ctx);
ctx->prev_code = ctx->clear_code;
- *stack_base_out = ctx->stack_base;
return LZW_OK;
}
@@ -301,30 +299,45 @@ static inline void lzw__table_add_entry(
/**
* Write values for this code to the output stack.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] code LZW code to output values for.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[in] code LZW code to output values for.
* \return Number of pixel values written.
*/
static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
+ void *restrict output,
uint32_t code)
{
- uint8_t *stack_pos = ctx->stack_base;
+ uint8_t *restrict output_pos = (uint8_t *)output;
struct lzw_table_entry * const table = ctx->table;
uint32_t count = table[code].count;
- stack_pos += count;
+ output_pos += count;
for (unsigned i = count; i != 0; i--) {
struct lzw_table_entry *entry = table + code;
- *--stack_pos = entry->value;
+ *--output_pos = entry->value;
code = entry->extends;
}
return count;
}
-/* Exported function, documented in lzw.h */
-lzw_result lzw_decode(struct lzw_ctx *ctx,
- uint32_t *written)
+/**
+ * Fill the LZW stack with decompressed data
+ *
+ * Ensure anything in output is used before calling this, as anything
+ * on the there before this call will be trampled.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] output Array to write output values into.
+ * \param[out] used Returns the number of values written.
+ * Use with `stack_base_out` value from previous
+ * lzw_decode_init() call.
+ * \return LZW_OK on success, or appropriate error code otherwise.
+ */
+static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
+ uint8_t *restrict output,
+ uint32_t *restrict used)
{
lzw_result res;
uint32_t code;
@@ -362,7 +375,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
}
}
- *written += lzw__write_pixels(ctx, code);
+ *used += lzw__write_pixels(ctx, output, code);
}
/* Store details of this code as "previous code" to the context. */
@@ -372,3 +385,13 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
return LZW_OK;
}
+
+/* Exported function, documented in lzw.h */
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t *restrict* const restrict data,
+ uint32_t *restrict used)
+{
+ *used = 0;
+ *data = ctx->stack_base;
+ return lzw__decode(ctx, ctx->stack_base, used);
+}
diff --git a/src/lzw.h b/src/lzw.h
index a4a58fc..dd0191e 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -74,23 +74,21 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
- uint8_t minimum_code_size,
- const uint8_t ** const stack_base_out);
+ uint8_t minimum_code_size);
/**
- * Fill the LZW stack with decompressed data
+ * Read a single LZW code and write into lzw context owned output buffer.
*
- * Ensure anything on the stack is used before calling this, as anything
- * on the stack before this call will be trampled.
+ * Ensure anything in output is used before calling this, as anything
+ * on the there before this call will be trampled.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[out] written Returns the number of values written.
- * Use with `stack_base_out` value from previous
- * lzw_decode_init() call.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] data Returns pointer to array of output values.
+ * \param[out] used Returns the number of values written to data.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
-lzw_result lzw_decode(
- struct lzw_ctx *ctx,
- uint32_t *written);
+lzw_result lzw_decode(struct lzw_ctx *ctx,
+ const uint8_t *restrict *const restrict data,
+ uint32_t *restrict used);
#endif
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=d60461e06b690ef4583d767fd7d5c99415622e98
commit d60461e06b690ef4583d767fd7d5c99415622e98
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
gif: Frame decoding: Rearrange for readability.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 0874ec9..1540e1d 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -641,7 +641,7 @@ gif__decode(gif_animation *gif,
unsigned int transparency_index;
const uint8_t *stack_base;
const uint8_t *stack_pos;
- uint32_t written = 0;
+ uint32_t available = 0;
gif_result ret = GIF_OK;
lzw_result res;
@@ -672,23 +672,9 @@ gif__decode(gif_animation *gif,
x = width;
while (x > 0) {
- if (written > 0) {
- unsigned burst_bytes = written;
- if (burst_bytes > x) {
- burst_bytes = x;
- }
- x -= burst_bytes;
- written -= burst_bytes;
- while (burst_bytes-- > 0) {
- register unsigned int colour;
- colour = *stack_pos++;
- if (colour != transparency_index) {
- *frame_scanline =
colour_table[colour];
- }
- frame_scanline++;
- }
- } else {
- res = lzw_decode(gif->lzw_ctx, &written);
+ unsigned row_available;
+ if (available == 0) {
+ res = lzw_decode(gif->lzw_ctx, &available);
if (res != LZW_OK) {
/* Unexpected end of frame, try to
recover */
if (res == LZW_OK_EOD) {
@@ -700,6 +686,18 @@ gif__decode(gif_animation *gif,
}
stack_pos = stack_base;
}
+
+ row_available = x < available ? x : available;
+ x -= row_available;
+ available -= row_available;
+ while (row_available-- > 0) {
+ register unsigned int colour;
+ colour = *stack_pos++;
+ if (colour != transparency_index) {
+ *frame_scanline = colour_table[colour];
+ }
+ frame_scanline++;
+ }
}
}
return ret;
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=ec5b110f5af6618dd250c13e6fed0abd8040e813
commit ec5b110f5af6618dd250c13e6fed0abd8040e813
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
gif: Frame decoding: Simplify transparency check.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 3b070b3..0874ec9 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -42,6 +42,9 @@
/** Transparent colour */
#define GIF_TRANSPARENT_COLOUR 0x00
+/** No transparency */
+#define GIF_NO_TRANSPARENCY (0xFFFFFFFFu)
+
/* GIF Flags */
#define GIF_FRAME_COMBINE 1
#define GIF_FRAME_CLEAR 2
@@ -635,6 +638,7 @@ gif__decode(gif_animation *gif,
unsigned int *restrict frame_data,
unsigned int *restrict colour_table)
{
+ unsigned int transparency_index;
const uint8_t *stack_base;
const uint8_t *stack_pos;
uint32_t written = 0;
@@ -649,6 +653,10 @@ gif__decode(gif_animation *gif,
return gif_error_from_lzw(res);
}
+ transparency_index = gif->frames[frame].transparency ?
+ gif->frames[frame].transparency_index :
+ GIF_NO_TRANSPARENCY;
+
stack_pos = stack_base;
for (unsigned int y = 0; y < height; y++) {
unsigned int x;
@@ -672,11 +680,9 @@ gif__decode(gif_animation *gif,
x -= burst_bytes;
written -= burst_bytes;
while (burst_bytes-- > 0) {
- register unsigned char colour;
+ register unsigned int colour;
colour = *stack_pos++;
- if (((gif->frames[frame].transparency)
&&
- (colour !=
gif->frames[frame].transparency_index)) ||
-
(!gif->frames[frame].transparency)) {
+ if (colour != transparency_index) {
*frame_scanline =
colour_table[colour];
}
frame_scanline++;
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=35079ae6fe202806f616cbbde19a5ff1aa964dc3
commit 35079ae6fe202806f616cbbde19a5ff1aa964dc3
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Remove written member from context.
Not needed now that clear codes are handled normally.
diff --git a/src/lzw.c b/src/lzw.c
index d7e7a04..d3e0dcf 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -83,7 +83,6 @@ struct lzw_ctx {
uint32_t table_size; /**< Next position in table to fill. */
/** Output value stack. */
- uint32_t written;
uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
/** LZW decode table. Generated during decode. */
@@ -302,13 +301,14 @@ static inline void lzw__table_add_entry(
/**
* Write values for this code to the output stack.
*
- * \param[in] ctx LZW reading context, updated.
- * \param[in] code LZW code to output values for.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] code LZW code to output values for.
+ * \return Number of pixel values written.
*/
-static inline void lzw__write_pixels(struct lzw_ctx *ctx,
+static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
uint32_t code)
{
- uint8_t *stack_pos = ctx->stack_base + ctx->written;
+ uint8_t *stack_pos = ctx->stack_base;
struct lzw_table_entry * const table = ctx->table;
uint32_t count = table[code].count;
@@ -319,8 +319,7 @@ static inline void lzw__write_pixels(struct lzw_ctx *ctx,
code = entry->extends;
}
- ctx->written += count;
- return;
+ return count;
}
/* Exported function, documented in lzw.h */
@@ -330,8 +329,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
lzw_result res;
uint32_t code;
- ctx->written = 0;
-
/* Get a new code from the input */
res = lzw__read_code(&ctx->input, ctx->code_size, &code);
if (res != LZW_OK) {
@@ -365,7 +362,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
}
}
- lzw__write_pixels(ctx, code);
+ *written += lzw__write_pixels(ctx, code);
}
/* Store details of this code as "previous code" to the context. */
@@ -373,7 +370,5 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
ctx->prev_code_count = ctx->table[code].count;
ctx->prev_code = code;
- *written = ctx->written;
-
return LZW_OK;
}
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=412a5acea5762690dcf22498530165a7221532e0
commit 412a5acea5762690dcf22498530165a7221532e0
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Adapt main code handling to handle clear codes too.
diff --git a/src/lzw.c b/src/lzw.c
index 3db65c3..d7e7a04 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -223,42 +223,16 @@ static inline lzw_result lzw__read_code(
/**
* Clear LZW code table.
*
- * \param[in] ctx LZW reading context, updated.
+ * \param[in] ctx LZW reading context, updated.
* \return LZW_OK or error code.
*/
-static lzw_result lzw__clear_codes(
+static inline void lzw__clear_table(
struct lzw_ctx *ctx)
{
- uint32_t code;
-
/* Reset table building context */
ctx->code_size = ctx->initial_code_size;
ctx->code_max = (1 << ctx->initial_code_size) - 1;
ctx->table_size = ctx->eoi_code + 1;
-
- /* There might be a sequence of clear codes, so process them all */
- do {
- lzw_result res = lzw__read_code(&ctx->input,
- ctx->code_size, &code);
- if (res != LZW_OK) {
- return res;
- }
- } while (code == ctx->clear_code);
-
- /* The initial code must be from the initial table. */
- if (code > ctx->clear_code) {
- return LZW_BAD_ICODE;
- }
-
- /* Record this initial code as "previous" code, needed during decode. */
- ctx->prev_code = code;
- ctx->prev_code_first = code;
- ctx->prev_code_count = 1;
-
- /* Reset the stack, and add first non-clear code added as first item. */
- ctx->stack_base[ctx->written++] = code;
-
- return LZW_OK;
}
@@ -298,10 +272,11 @@ lzw_result lzw_decode_init(
table[i].count = 1;
}
- ctx->written = 0;
+ lzw__clear_table(ctx);
+ ctx->prev_code = ctx->clear_code;
*stack_base_out = ctx->stack_base;
- return lzw__clear_codes(ctx);
+ return LZW_OK;
}
/**
@@ -355,6 +330,8 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
lzw_result res;
uint32_t code;
+ ctx->written = 0;
+
/* Get a new code from the input */
res = lzw__read_code(&ctx->input, ctx->code_size, &code);
if (res != LZW_OK) {
@@ -362,35 +339,33 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
}
/* Handle the new code */
- if (code == ctx->clear_code) {
- /* Got Clear code */
- res = lzw__clear_codes(ctx);
- if (res == LZW_OK) {
- *written = ctx->written;
- ctx->written = 0;
- }
- return res;
-
- } else if (code == ctx->eoi_code) {
+ if (code == ctx->eoi_code) {
/* Got End of Information code */
return LZW_EOI_CODE;
} else if (code > ctx->table_size) {
/* Code is invalid */
return LZW_BAD_CODE;
- }
- if (ctx->table_size < LZW_DICTIONARY_ENTRY_MAX) {
- uint32_t size = ctx->table_size;
- lzw__table_add_entry(ctx, (code < size) ?
- ctx->table[code].first :
- ctx->prev_code_first);
-
- /* Ensure code size is increased, if needed. */
- if (size == ctx->code_max && ctx->code_size < LZW_CODE_MAX) {
- ctx->code_size++;
- ctx->code_max = (1 << ctx->code_size) - 1;
+ } else if (code == ctx->clear_code) {
+ lzw__clear_table(ctx);
+ } else {
+ if (ctx->prev_code != ctx->clear_code &&
+ ctx->table_size < LZW_DICTIONARY_ENTRY_MAX) {
+ uint32_t size = ctx->table_size;
+ lzw__table_add_entry(ctx, (code < size) ?
+ ctx->table[code].first :
+ ctx->prev_code_first);
+
+ /* Ensure code size is increased, if needed. */
+ if (size == ctx->code_max &&
+ ctx->code_size < LZW_CODE_MAX) {
+ ctx->code_size++;
+ ctx->code_max = (1 << ctx->code_size) - 1;
+ }
}
+
+ lzw__write_pixels(ctx, code);
}
/* Store details of this code as "previous code" to the context. */
@@ -398,10 +373,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
ctx->prev_code_count = ctx->table[code].count;
ctx->prev_code = code;
- lzw__write_pixels(ctx, code);
-
*written = ctx->written;
- ctx->written = 0;
return LZW_OK;
}
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=73f6376fc3ffbed45576a12f69675e09c2b02d1f
commit 73f6376fc3ffbed45576a12f69675e09c2b02d1f
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Output values in picture order.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index ed394a2..3b070b3 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -637,17 +637,19 @@ gif__decode(gif_animation *gif,
{
const uint8_t *stack_base;
const uint8_t *stack_pos;
+ 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, &stack_base, &stack_pos);
+ minimum_code_size, &stack_base);
if (res != LZW_OK) {
return gif_error_from_lzw(res);
}
+ stack_pos = stack_base;
for (unsigned int y = 0; y < height; y++) {
unsigned int x;
unsigned int decode_y;
@@ -660,21 +662,18 @@ gif__decode(gif_animation *gif,
}
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 (written > 0) {
+ unsigned burst_bytes = written;
if (burst_bytes > x) {
burst_bytes = x;
}
x -= burst_bytes;
+ written -= burst_bytes;
while (burst_bytes-- > 0) {
register unsigned char colour;
- colour = *--stack_pos;
+ colour = *stack_pos++;
if (((gif->frames[frame].transparency)
&&
(colour !=
gif->frames[frame].transparency_index)) ||
(!gif->frames[frame].transparency)) {
@@ -683,7 +682,7 @@ gif__decode(gif_animation *gif,
frame_scanline++;
}
} else {
- res = lzw_decode(gif->lzw_ctx, &stack_pos);
+ res = lzw_decode(gif->lzw_ctx, &written);
if (res != LZW_OK) {
/* Unexpected end of frame, try to
recover */
if (res == LZW_OK_EOD) {
@@ -693,10 +692,10 @@ gif__decode(gif_animation *gif,
}
break;
}
+ stack_pos = stack_base;
}
}
}
-
return ret;
}
diff --git a/src/lzw.c b/src/lzw.c
index d9b4571..3db65c3 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -83,6 +83,7 @@ struct lzw_ctx {
uint32_t table_size; /**< Next position in table to fill. */
/** Output value stack. */
+ uint32_t written;
uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
/** LZW decode table. Generated during decode. */
@@ -223,15 +224,12 @@ static inline lzw_result lzw__read_code(
* Clear LZW code table.
*
* \param[in] ctx LZW reading context, updated.
- * \param[out] stack_pos_out Returns current stack position.
* \return LZW_OK or error code.
*/
static lzw_result lzw__clear_codes(
- struct lzw_ctx *ctx,
- const uint8_t ** const stack_pos_out)
+ struct lzw_ctx *ctx)
{
uint32_t code;
- uint8_t *stack_pos;
/* Reset table building context */
ctx->code_size = ctx->initial_code_size;
@@ -258,10 +256,8 @@ static lzw_result lzw__clear_codes(
ctx->prev_code_count = 1;
/* Reset the stack, and add first non-clear code added as first item. */
- stack_pos = ctx->stack_base;
- *stack_pos++ = code;
+ ctx->stack_base[ctx->written++] = code;
- *stack_pos_out = stack_pos;
return LZW_OK;
}
@@ -273,8 +269,7 @@ lzw_result lzw_decode_init(
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
uint8_t minimum_code_size,
- const uint8_t ** const stack_base_out,
- const uint8_t ** const stack_pos_out)
+ const uint8_t ** const stack_base_out)
{
struct lzw_table_entry *table = ctx->table;
@@ -303,8 +298,10 @@ lzw_result lzw_decode_init(
table[i].count = 1;
}
+ ctx->written = 0;
+
*stack_base_out = ctx->stack_base;
- return lzw__clear_codes(ctx, stack_pos_out);
+ return lzw__clear_codes(ctx);
}
/**
@@ -332,32 +329,28 @@ static inline void lzw__table_add_entry(
*
* \param[in] ctx LZW reading context, updated.
* \param[in] code LZW code to output values for.
- * \param[out] stack_pos_out Returns current stack position.
- * There are `stack_pos_out - ctx->stack_base`
- * current stack entries.
*/
static inline void lzw__write_pixels(struct lzw_ctx *ctx,
- uint32_t code,
- const uint8_t ** const stack_pos_out)
+ uint32_t code)
{
- uint8_t *stack_pos = ctx->stack_base;
- uint32_t clear_code = ctx->clear_code;
+ uint8_t *stack_pos = ctx->stack_base + ctx->written;
struct lzw_table_entry * const table = ctx->table;
+ uint32_t count = table[code].count;
- while (code > clear_code) {
+ stack_pos += count;
+ for (unsigned i = count; i != 0; i--) {
struct lzw_table_entry *entry = table + code;
- *stack_pos++ = entry->value;
+ *--stack_pos = entry->value;
code = entry->extends;
}
- *stack_pos++ = table[code].value;
- *stack_pos_out = stack_pos;
+ ctx->written += count;
return;
}
/* Exported function, documented in lzw.h */
lzw_result lzw_decode(struct lzw_ctx *ctx,
- const uint8_t ** const stack_pos_out)
+ uint32_t *written)
{
lzw_result res;
uint32_t code;
@@ -371,7 +364,12 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
/* Handle the new code */
if (code == ctx->clear_code) {
/* Got Clear code */
- return lzw__clear_codes(ctx, stack_pos_out);
+ res = lzw__clear_codes(ctx);
+ if (res == LZW_OK) {
+ *written = ctx->written;
+ ctx->written = 0;
+ }
+ return res;
} else if (code == ctx->eoi_code) {
/* Got End of Information code */
@@ -400,6 +398,10 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
ctx->prev_code_count = ctx->table[code].count;
ctx->prev_code = code;
- lzw__write_pixels(ctx, code, stack_pos_out);
+ lzw__write_pixels(ctx, code);
+
+ *written = ctx->written;
+ ctx->written = 0;
+
return LZW_OK;
}
diff --git a/src/lzw.h b/src/lzw.h
index 888526e..a4a58fc 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -67,9 +67,6 @@ void lzw_context_destroy(
* 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.
- * \param[out] stack_pos_out Returns current stack position.
- * There are `stack_pos_out - stack_base_out`
- * current stack entries.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_init(
@@ -78,8 +75,7 @@ lzw_result lzw_decode_init(
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
uint8_t minimum_code_size,
- const uint8_t ** const stack_base_out,
- const uint8_t ** const stack_pos_out);
+ const uint8_t ** const stack_base_out);
/**
* Fill the LZW stack with decompressed data
@@ -87,19 +83,14 @@ lzw_result lzw_decode_init(
* Ensure anything on the stack is used before calling this, as anything
* on the stack before this call will be trampled.
*
- * Caller does not own `stack_pos_out`.
- *
- * \param[in] ctx LZW reading context, updated.
- * \param[out] stack_pos_out Returns current stack position.
- * Use with `stack_base_out` value from previous
- * lzw_decode_init() call.
- * There are `stack_pos_out - stack_base_out`
- * current stack entries.
+ * \param[in] ctx LZW reading context, updated.
+ * \param[out] written Returns the number of values written.
+ * Use with `stack_base_out` value from previous
+ * lzw_decode_init() call.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode(
struct lzw_ctx *ctx,
- const uint8_t ** const stack_pos_out);
-
+ uint32_t *written);
#endif
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=a7183f1ea70b3f3c722b27f97c5d494ada1be231
commit a7183f1ea70b3f3c722b27f97c5d494ada1be231
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Store code's value count in table.
diff --git a/src/lzw.c b/src/lzw.c
index 6371513..d9b4571 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -58,6 +58,7 @@ struct lzw_read_ctx {
struct lzw_table_entry {
uint8_t value; /**< Last value for record ending at entry. */
uint8_t first; /**< First value in entry's entire record. */
+ uint16_t count; /**< Count of values in this entry's record. */
uint16_t extends; /**< Offset in table to previous entry. */
};
@@ -69,6 +70,7 @@ struct lzw_ctx {
uint32_t prev_code; /**< Code read from input previously. */
uint32_t prev_code_first; /**< First value of previous code. */
+ uint32_t prev_code_count; /**< Total values for previous code. */
uint32_t initial_code_size; /**< Starting LZW code size. */
@@ -253,6 +255,7 @@ static lzw_result lzw__clear_codes(
/* Record this initial code as "previous" code, needed during decode. */
ctx->prev_code = code;
ctx->prev_code_first = code;
+ ctx->prev_code_count = 1;
/* Reset the stack, and add first non-clear code added as first item. */
stack_pos = ctx->stack_base;
@@ -297,6 +300,7 @@ lzw_result lzw_decode_init(
for (uint32_t i = 0; i < ctx->clear_code; ++i) {
table[i].first = i;
table[i].value = i;
+ table[i].count = 1;
}
*stack_base_out = ctx->stack_base;
@@ -317,6 +321,7 @@ static inline void lzw__table_add_entry(
entry->value = code;
entry->first = ctx->prev_code_first;
+ entry->count = ctx->prev_code_count + 1;
entry->extends = ctx->prev_code;
ctx->table_size++;
@@ -392,6 +397,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
/* Store details of this code as "previous code" to the context. */
ctx->prev_code_first = ctx->table[code].first;
+ ctx->prev_code_count = ctx->table[code].count;
ctx->prev_code = code;
lzw__write_pixels(ctx, code, stack_pos_out);
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=71a32374233598177e06ba9ee6214b9379bd40ba
commit 71a32374233598177e06ba9ee6214b9379bd40ba
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
gif: Split out gif frame data decode.
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 512ebfe..ed394a2 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -623,6 +623,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
*
@@ -643,11 +720,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) {
@@ -801,10 +875,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
*/
@@ -868,62 +938,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,
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=9520f18f7290ba4a9080be62ac9d2dbc957866a8
commit 9520f18f7290ba4a9080be62ac9d2dbc957866a8
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Rename a bunch of structures, functions and variables.
new_code -> code
last_value -> value
first_value -> first
previous_entry -> extends
current_entry -> table_size
previous_code -> prev_code
previous_code_first -> prev_code_first
current_code_size -> code_size
current_code_size_max -> code_max
lzw__next_code -> lzw_read_code
diff --git a/src/lzw.c b/src/lzw.c
index 61093bb..6371513 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -21,7 +21,7 @@
* Decoder for GIF LZW data.
*/
-/** Maximum number of dictionary entries. */
+/** Maximum number of table entries. */
#define LZW_DICTIONARY_ENTRY_MAX (1u << LZW_CODE_MAX)
/**
@@ -46,45 +46,45 @@ struct lzw_read_ctx {
};
/**
- * LZW dictionary entry.
+ * LZW table entry.
*
- * Records in the dictionary are composed of 1 or more entries.
- * Entries point to previous entries which can be followed to compose
+ * Records in the table are composed of 1 or more entries.
+ * Entries refer to the entry they extend which can be followed to compose
* the complete record. To compose the record in reverse order, take
- * the `last_value` from each entry, and move to the previous entry.
- * If the previous_entry's index is < the current clear_code, then it
+ * the `value` from each entry, and move to the entry it extends.
+ * If the extended entries index is < the current clear_code, then it
* is the last entry in the record.
*/
-struct lzw_dictionary_entry {
- uint8_t last_value; /**< Last value for record ending at entry. */
- uint8_t first_value; /**< First value for entry's record. */
- uint16_t previous_entry; /**< Offset in dictionary to previous entry. */
+struct lzw_table_entry {
+ uint8_t value; /**< Last value for record ending at entry. */
+ uint8_t first; /**< First value in entry's entire record. */
+ uint16_t extends; /**< Offset in table to previous entry. */
};
/**
* LZW decompression context.
*/
struct lzw_ctx {
- /** Input reading context */
- struct lzw_read_ctx input;
+ struct lzw_read_ctx input; /**< Input reading context */
- uint32_t previous_code; /**< Code read from input previously. */
- uint32_t previous_code_first; /**< First value of previous code. */
+ uint32_t prev_code; /**< Code read from input previously. */
+ uint32_t prev_code_first; /**< First value of previous code. */
- uint32_t initial_code_size; /**< Starting LZW code size. */
- uint32_t current_code_size; /**< Current LZW code size. */
- uint32_t current_code_size_max; /**< Max code value for current size. */
+ uint32_t initial_code_size; /**< Starting LZW code size. */
+
+ uint32_t code_size; /**< Current LZW code size. */
+ uint32_t code_max; /**< Max code value for current code size. */
uint32_t clear_code; /**< Special Clear code value */
uint32_t eoi_code; /**< Special End of Information code value */
- uint32_t current_entry; /**< Next position in table to fill. */
+ uint32_t table_size; /**< Next position in table to fill. */
/** Output value stack. */
uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
- /** LZW decode dictionary. Generated during decode. */
- struct lzw_dictionary_entry table[LZW_DICTIONARY_ENTRY_MAX];
+ /** LZW decode table. Generated during decode. */
+ struct lzw_table_entry table[LZW_DICTIONARY_ENTRY_MAX];
};
@@ -155,7 +155,7 @@ static lzw_result lzw__block_advance(struct lzw_read_ctx
*ctx)
* \param[out] code_out Returns an LZW code on success.
* \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
*/
-static inline lzw_result lzw__next_code(
+static inline lzw_result lzw__read_code(
struct lzw_read_ctx *ctx,
uint8_t code_size,
uint32_t *code_out)
@@ -218,7 +218,7 @@ static inline lzw_result lzw__next_code(
/**
- * Clear LZW code dictionary.
+ * Clear LZW code table.
*
* \param[in] ctx LZW reading context, updated.
* \param[out] stack_pos_out Returns current stack position.
@@ -231,28 +231,28 @@ static lzw_result lzw__clear_codes(
uint32_t code;
uint8_t *stack_pos;
- /* Reset dictionary building context */
- ctx->current_code_size = ctx->initial_code_size;
- ctx->current_code_size_max = (1 << ctx->initial_code_size) - 1;
- ctx->current_entry = ctx->eoi_code + 1;
+ /* Reset table building context */
+ ctx->code_size = ctx->initial_code_size;
+ ctx->code_max = (1 << ctx->initial_code_size) - 1;
+ ctx->table_size = ctx->eoi_code + 1;
/* There might be a sequence of clear codes, so process them all */
do {
- lzw_result res = lzw__next_code(&ctx->input,
- ctx->current_code_size, &code);
+ lzw_result res = lzw__read_code(&ctx->input,
+ ctx->code_size, &code);
if (res != LZW_OK) {
return res;
}
} while (code == ctx->clear_code);
- /* The initial code must be from the initial dictionary. */
+ /* The initial code must be from the initial table. */
if (code > ctx->clear_code) {
return LZW_BAD_ICODE;
}
/* Record this initial code as "previous" code, needed during decode. */
- ctx->previous_code = code;
- ctx->previous_code_first = code;
+ ctx->prev_code = code;
+ ctx->prev_code_first = code;
/* Reset the stack, and add first non-clear code added as first item. */
stack_pos = ctx->stack_base;
@@ -273,7 +273,7 @@ lzw_result lzw_decode_init(
const uint8_t ** const stack_base_out,
const uint8_t ** const stack_pos_out)
{
- struct lzw_dictionary_entry *table = ctx->table;
+ struct lzw_table_entry *table = ctx->table;
if (minimum_code_size >= LZW_CODE_MAX) {
return LZW_BAD_ICODE;
@@ -287,16 +287,16 @@ lzw_result lzw_decode_init(
ctx->input.sb_bit = 0;
ctx->input.sb_bit_count = 0;
- /* Initialise the dictionary building context */
+ /* Initialise the table building context */
ctx->initial_code_size = minimum_code_size + 1;
ctx->clear_code = (1 << minimum_code_size) + 0;
ctx->eoi_code = (1 << minimum_code_size) + 1;
- /* Initialise the standard dictionary entries */
+ /* Initialise the standard table entries */
for (uint32_t i = 0; i < ctx->clear_code; ++i) {
- table[i].first_value = i;
- table[i].last_value = i;
+ table[i].first = i;
+ table[i].value = i;
}
*stack_base_out = ctx->stack_base;
@@ -304,22 +304,22 @@ lzw_result lzw_decode_init(
}
/**
- * Create new dictionary entry.
+ * Create new table entry.
*
* \param[in] ctx LZW reading context, updated.
- * \param[in] code Last value code for new dictionary entry.
+ * \param[in] code Last value code for new table entry.
*/
-static inline void lzw__dictionary_add_entry(
+static inline void lzw__table_add_entry(
struct lzw_ctx *ctx,
uint32_t code)
{
- struct lzw_dictionary_entry *entry = &ctx->table[ctx->current_entry];
+ struct lzw_table_entry *entry = &ctx->table[ctx->table_size];
- entry->last_value = code;
- entry->first_value = ctx->previous_code_first;
- entry->previous_entry = ctx->previous_code;
+ entry->value = code;
+ entry->first = ctx->prev_code_first;
+ entry->extends = ctx->prev_code;
- ctx->current_entry++;
+ ctx->table_size++;
}
/**
@@ -337,14 +337,14 @@ static inline void lzw__write_pixels(struct lzw_ctx *ctx,
{
uint8_t *stack_pos = ctx->stack_base;
uint32_t clear_code = ctx->clear_code;
- struct lzw_dictionary_entry * const table = ctx->table;
+ struct lzw_table_entry * const table = ctx->table;
while (code > clear_code) {
- struct lzw_dictionary_entry *entry = table + code;
- *stack_pos++ = entry->last_value;
- code = entry->previous_entry;
+ struct lzw_table_entry *entry = table + code;
+ *stack_pos++ = entry->value;
+ code = entry->extends;
}
- *stack_pos++ = table[code].last_value;
+ *stack_pos++ = table[code].value;
*stack_pos_out = stack_pos;
return;
@@ -355,47 +355,45 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t ** const stack_pos_out)
{
lzw_result res;
- uint32_t code_new;
- uint32_t current_entry = ctx->current_entry;
+ uint32_t code;
/* Get a new code from the input */
- res = lzw__next_code(&ctx->input, ctx->current_code_size, &code_new);
+ res = lzw__read_code(&ctx->input, ctx->code_size, &code);
if (res != LZW_OK) {
return res;
}
/* Handle the new code */
- if (code_new == ctx->clear_code) {
+ if (code == ctx->clear_code) {
/* Got Clear code */
return lzw__clear_codes(ctx, stack_pos_out);
- } else if (code_new == ctx->eoi_code) {
+ } else if (code == ctx->eoi_code) {
/* Got End of Information code */
return LZW_EOI_CODE;
- } else if (code_new > current_entry) {
+ } else if (code > ctx->table_size) {
/* Code is invalid */
return LZW_BAD_CODE;
}
- if (current_entry < LZW_DICTIONARY_ENTRY_MAX) {
- lzw__dictionary_add_entry(ctx, (code_new < current_entry) ?
- ctx->table[code_new].first_value :
- ctx->previous_code_first);
+ if (ctx->table_size < LZW_DICTIONARY_ENTRY_MAX) {
+ uint32_t size = ctx->table_size;
+ lzw__table_add_entry(ctx, (code < size) ?
+ ctx->table[code].first :
+ ctx->prev_code_first);
/* Ensure code size is increased, if needed. */
- if (current_entry == ctx->current_code_size_max &&
- ctx->current_code_size < LZW_CODE_MAX) {
- ctx->current_code_size++;
- ctx->current_code_size_max =
- (1 << ctx->current_code_size) - 1;
+ if (size == ctx->code_max && ctx->code_size < LZW_CODE_MAX) {
+ ctx->code_size++;
+ ctx->code_max = (1 << ctx->code_size) - 1;
}
}
/* Store details of this code as "previous code" to the context. */
- ctx->previous_code_first = ctx->table[code_new].first_value;
- ctx->previous_code = code_new;
+ ctx->prev_code_first = ctx->table[code].first;
+ ctx->prev_code = code;
- lzw__write_pixels(ctx, code_new, stack_pos_out);
+ lzw__write_pixels(ctx, code, stack_pos_out);
return LZW_OK;
}
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=cf304dc469bfe688f8ae70c6102803095edfd0df
commit cf304dc469bfe688f8ae70c6102803095edfd0df
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Split out output writing.
diff --git a/src/lzw.c b/src/lzw.c
index 8f2d5f2..61093bb 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -322,16 +322,41 @@ static inline void lzw__dictionary_add_entry(
ctx->current_entry++;
}
+/**
+ * Write values for this code to the output stack.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] code LZW code to output values for.
+ * \param[out] stack_pos_out Returns current stack position.
+ * There are `stack_pos_out - ctx->stack_base`
+ * current stack entries.
+ */
+static inline void lzw__write_pixels(struct lzw_ctx *ctx,
+ uint32_t code,
+ const uint8_t ** const stack_pos_out)
+{
+ uint8_t *stack_pos = ctx->stack_base;
+ uint32_t clear_code = ctx->clear_code;
+ struct lzw_dictionary_entry * const table = ctx->table;
+
+ while (code > clear_code) {
+ struct lzw_dictionary_entry *entry = table + code;
+ *stack_pos++ = entry->last_value;
+ code = entry->previous_entry;
+ }
+ *stack_pos++ = table[code].last_value;
+
+ *stack_pos_out = stack_pos;
+ return;
+}
+
/* Exported function, documented in lzw.h */
lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t ** const stack_pos_out)
{
lzw_result res;
uint32_t code_new;
- uint8_t *stack_pos = ctx->stack_base;
- uint32_t clear_code = ctx->clear_code;
uint32_t current_entry = ctx->current_entry;
- struct lzw_dictionary_entry * const table = ctx->table;
/* Get a new code from the input */
res = lzw__next_code(&ctx->input, ctx->current_code_size, &code_new);
@@ -340,7 +365,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
}
/* Handle the new code */
- if (code_new == clear_code) {
+ if (code_new == ctx->clear_code) {
/* Got Clear code */
return lzw__clear_codes(ctx, stack_pos_out);
@@ -355,7 +380,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
if (current_entry < LZW_DICTIONARY_ENTRY_MAX) {
lzw__dictionary_add_entry(ctx, (code_new < current_entry) ?
- table[code_new].first_value :
+ ctx->table[code_new].first_value :
ctx->previous_code_first);
/* Ensure code size is increased, if needed. */
@@ -368,17 +393,9 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
}
/* Store details of this code as "previous code" to the context. */
- ctx->previous_code_first = table[code_new].first_value;
+ ctx->previous_code_first = ctx->table[code_new].first_value;
ctx->previous_code = code_new;
- /* Put data for this code on output stack. */
- while (code_new > clear_code) {
- struct lzw_dictionary_entry *entry = table + code_new;
- *stack_pos++ = entry->last_value;
- code_new = entry->previous_entry;
- }
- *stack_pos++ = table[code_new].last_value;
-
- *stack_pos_out = stack_pos;
+ lzw__write_pixels(ctx, code_new, stack_pos_out);
return LZW_OK;
}
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=62a814e980ea22b289b92b967cc0be7f373029ca
commit 62a814e980ea22b289b92b967cc0be7f373029ca
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Rename minimum_code_size to match what it's called in spec.
diff --git a/src/lzw.c b/src/lzw.c
index 8b3e472..8f2d5f2 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -269,13 +269,13 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
- uint8_t code_size,
+ uint8_t minimum_code_size,
const uint8_t ** const stack_base_out,
const uint8_t ** const stack_pos_out)
{
struct lzw_dictionary_entry *table = ctx->table;
- if (code_size >= LZW_CODE_MAX) {
+ if (minimum_code_size >= LZW_CODE_MAX) {
return LZW_BAD_ICODE;
}
@@ -288,10 +288,10 @@ lzw_result lzw_decode_init(
ctx->input.sb_bit_count = 0;
/* Initialise the dictionary building context */
- ctx->initial_code_size = code_size + 1;
+ ctx->initial_code_size = minimum_code_size + 1;
- ctx->clear_code = (1 << code_size) + 0;
- ctx->eoi_code = (1 << code_size) + 1;
+ ctx->clear_code = (1 << minimum_code_size) + 0;
+ ctx->eoi_code = (1 << minimum_code_size) + 1;
/* Initialise the standard dictionary entries */
for (uint32_t i = 0; i < ctx->clear_code; ++i) {
diff --git a/src/lzw.h b/src/lzw.h
index 385b425..888526e 100644
--- a/src/lzw.h
+++ b/src/lzw.h
@@ -65,7 +65,7 @@ void lzw_context_destroy(
* \param[in] compressed_data_len Byte length of compressed data.
* \param[in] compressed_data_pos Start position in data. Must be position
* of a size byte at sub-block start.
- * \param[in] code_size The initial LZW code size to use.
+ * \param[in] minimum_code_size The LZW Minimum Code Size.
* \param[out] stack_base_out Returns base of decompressed data stack.
* \param[out] stack_pos_out Returns current stack position.
* There are `stack_pos_out - stack_base_out`
@@ -77,7 +77,7 @@ lzw_result lzw_decode_init(
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
- uint8_t code_size,
+ uint8_t minimum_code_size,
const uint8_t ** const stack_base_out,
const uint8_t ** const stack_pos_out);
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=728be940120d8c63b7c44df45e0203671158116b
commit 728be940120d8c63b7c44df45e0203671158116b
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Slight simplification of clear code handling.
diff --git a/src/lzw.c b/src/lzw.c
index 55bb4f8..8b3e472 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -232,9 +232,9 @@ static lzw_result lzw__clear_codes(
uint8_t *stack_pos;
/* Reset dictionary building context */
- ctx->current_code_size = ctx->initial_code_size + 1;
- ctx->current_code_size_max = (1 << ctx->current_code_size) - 1;
- ctx->current_entry = (1 << ctx->initial_code_size) + 2;
+ ctx->current_code_size = ctx->initial_code_size;
+ ctx->current_code_size_max = (1 << ctx->initial_code_size) - 1;
+ ctx->current_entry = ctx->eoi_code + 1;
/* There might be a sequence of clear codes, so process them all */
do {
@@ -288,7 +288,7 @@ lzw_result lzw_decode_init(
ctx->input.sb_bit_count = 0;
/* Initialise the dictionary building context */
- ctx->initial_code_size = code_size;
+ ctx->initial_code_size = code_size + 1;
ctx->clear_code = (1 << code_size) + 0;
ctx->eoi_code = (1 << code_size) + 1;
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=ce2543b41e3394c5cf3161d49f1561ba34f674a2
commit ce2543b41e3394c5cf3161d49f1561ba34f674a2
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Avoid code size increment check when dictionary is full.
diff --git a/src/lzw.c b/src/lzw.c
index 1d145b4..55bb4f8 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -357,11 +357,10 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
lzw__dictionary_add_entry(ctx, (code_new < current_entry) ?
table[code_new].first_value :
ctx->previous_code_first);
- }
- /* Ensure code size is increased, if needed. */
- if (current_entry == ctx->current_code_size_max) {
- if (ctx->current_code_size < LZW_CODE_MAX) {
+ /* Ensure code size is increased, if needed. */
+ if (current_entry == ctx->current_code_size_max &&
+ ctx->current_code_size < LZW_CODE_MAX) {
ctx->current_code_size++;
ctx->current_code_size_max =
(1 << ctx->current_code_size) - 1;
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=55c00227e1ad7cd7e03cc377fdaf052d57a56a06
commit 55c00227e1ad7cd7e03cc377fdaf052d57a56a06
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Split out dictionary augmentation.
diff --git a/src/lzw.c b/src/lzw.c
index a5097ab..1d145b4 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -303,6 +303,24 @@ lzw_result lzw_decode_init(
return lzw__clear_codes(ctx, stack_pos_out);
}
+/**
+ * Create new dictionary entry.
+ *
+ * \param[in] ctx LZW reading context, updated.
+ * \param[in] code Last value code for new dictionary entry.
+ */
+static inline void lzw__dictionary_add_entry(
+ struct lzw_ctx *ctx,
+ uint32_t code)
+{
+ struct lzw_dictionary_entry *entry = &ctx->table[ctx->current_entry];
+
+ entry->last_value = code;
+ entry->first_value = ctx->previous_code_first;
+ entry->previous_entry = ctx->previous_code;
+
+ ctx->current_entry++;
+}
/* Exported function, documented in lzw.h */
lzw_result lzw_decode(struct lzw_ctx *ctx,
@@ -310,7 +328,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
{
lzw_result res;
uint32_t code_new;
- uint8_t last_value;
uint8_t *stack_pos = ctx->stack_base;
uint32_t clear_code = ctx->clear_code;
uint32_t current_entry = ctx->current_entry;
@@ -334,22 +351,12 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
} else if (code_new > current_entry) {
/* Code is invalid */
return LZW_BAD_CODE;
-
- } else if (code_new < current_entry) {
- /* Code is in table */
- last_value = table[code_new].first_value;
- } else {
- /* Code not in table */
- last_value = ctx->previous_code_first;
}
- /* Add to the dictionary, only if there's space */
if (current_entry < LZW_DICTIONARY_ENTRY_MAX) {
- struct lzw_dictionary_entry *entry = table + current_entry;
- entry->last_value = last_value;
- entry->first_value = ctx->previous_code_first;
- entry->previous_entry = ctx->previous_code;
- ctx->current_entry++;
+ lzw__dictionary_add_entry(ctx, (code_new < current_entry) ?
+ table[code_new].first_value :
+ ctx->previous_code_first);
}
/* Ensure code size is increased, if needed. */
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=86786f4cc6800fa6c6282f8a87e2defacebeb94d
commit 86786f4cc6800fa6c6282f8a87e2defacebeb94d
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Create #define for number of dictionary entry slots.
diff --git a/src/lzw.c b/src/lzw.c
index 16e1a72..a5097ab 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -21,6 +21,8 @@
* Decoder for GIF LZW data.
*/
+/** Maximum number of dictionary entries. */
+#define LZW_DICTIONARY_ENTRY_MAX (1u << LZW_CODE_MAX)
/**
* Context for reading LZW data.
@@ -79,10 +81,10 @@ struct lzw_ctx {
uint32_t current_entry; /**< Next position in table to fill. */
/** Output value stack. */
- uint8_t stack_base[1 << LZW_CODE_MAX];
+ uint8_t stack_base[LZW_DICTIONARY_ENTRY_MAX];
/** LZW decode dictionary. Generated during decode. */
- struct lzw_dictionary_entry table[1 << LZW_CODE_MAX];
+ struct lzw_dictionary_entry table[LZW_DICTIONARY_ENTRY_MAX];
};
@@ -342,7 +344,7 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
}
/* Add to the dictionary, only if there's space */
- if (current_entry < (1 << LZW_CODE_MAX)) {
+ if (current_entry < LZW_DICTIONARY_ENTRY_MAX) {
struct lzw_dictionary_entry *entry = table + current_entry;
entry->last_value = last_value;
entry->first_value = ctx->previous_code_first;
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=d8e8d3cceef907f798276014ebdfed7c370fb866
commit d8e8d3cceef907f798276014ebdfed7c370fb866
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
lzw: Simplify new code handling.
The tiny overhead of an extra time through the output loop
is worth the simpler code.
diff --git a/src/lzw.c b/src/lzw.c
index 1f85496..16e1a72 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -4,6 +4,7 @@
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2017 Michael Drake <[email protected]>
+ * Copyright 2021 Michael Drake <[email protected]>
*/
#include <assert.h>
@@ -307,7 +308,6 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
{
lzw_result res;
uint32_t code_new;
- uint32_t code_out;
uint8_t last_value;
uint8_t *stack_pos = ctx->stack_base;
uint32_t clear_code = ctx->clear_code;
@@ -335,12 +335,9 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
} else if (code_new < current_entry) {
/* Code is in table */
- code_out = code_new;
last_value = table[code_new].first_value;
} else {
/* Code not in table */
- *stack_pos++ = ctx->previous_code_first;
- code_out = ctx->previous_code;
last_value = ctx->previous_code_first;
}
@@ -366,15 +363,13 @@ lzw_result lzw_decode(struct lzw_ctx *ctx,
ctx->previous_code_first = table[code_new].first_value;
ctx->previous_code = code_new;
- /* Put rest of data for this code on output stack.
- * Note, in the case of "code not in table", the last entry of the
- * current code has already been placed on the stack above. */
- while (code_out > clear_code) {
- struct lzw_dictionary_entry *entry = table + code_out;
+ /* Put data for this code on output stack. */
+ while (code_new > clear_code) {
+ struct lzw_dictionary_entry *entry = table + code_new;
*stack_pos++ = entry->last_value;
- code_out = entry->previous_entry;
+ code_new = entry->previous_entry;
}
- *stack_pos++ = table[code_out].last_value;
+ *stack_pos++ = table[code_new].last_value;
*stack_pos_out = stack_pos;
return LZW_OK;
-----------------------------------------------------------------------
Summary of changes:
src/libnsgif.c | 49 ++++++++++++++++---------------------------------
test/decode_gif.c | 4 ++++
2 files changed, 20 insertions(+), 33 deletions(-)
diff --git a/src/libnsgif.c b/src/libnsgif.c
index fb2577c..3c49218 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -82,34 +82,17 @@ gif_initialise_sprite(gif_animation *gif,
unsigned int width,
unsigned int height)
{
- unsigned int max_width;
- unsigned int max_height;
- struct bitmap *buffer;
-
- /* Check if we've changed */
- if ((width <= gif->width) && (height <= gif->height)) {
+ /* Already allocated? */
+ if (gif->frame_image) {
return GIF_OK;
}
- /* Get our maximum values */
- max_width = (width > gif->width) ? width : gif->width;
- max_height = (height > gif->height) ? height : gif->height;
-
- /* Allocate some more memory */
assert(gif->bitmap_callbacks.bitmap_create);
- buffer = gif->bitmap_callbacks.bitmap_create(max_width, max_height);
- if (buffer == NULL) {
+ gif->frame_image = gif->bitmap_callbacks.bitmap_create(width, height);
+ if (gif->frame_image == NULL) {
return GIF_INSUFFICIENT_MEMORY;
}
- assert(gif->bitmap_callbacks.bitmap_destroy);
- gif->bitmap_callbacks.bitmap_destroy(gif->frame_image);
- gif->frame_image = buffer;
- gif->width = max_width;
- gif->height = max_height;
-
- /* Invalidate our currently decoded image */
- gif->decoded_frame = GIF_INVALID_FRAME;
return GIF_OK;
}
@@ -395,10 +378,12 @@ static gif_result gif_initialise_frame(gif_animation *gif)
gif->frames[frame].redraw_required =
((gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) ||
(gif->frames[frame].disposal_method == GIF_FRAME_RESTORE));
- /* Boundary checking - shouldn't ever happen except with junk data */
- if (gif_initialise_sprite(gif, (offset_x + width), (offset_y +
height))) {
- return GIF_INSUFFICIENT_MEMORY;
- }
+ /* Frame size may have grown.
+ */
+ gif->width = (offset_x + width > gif->width) ?
+ offset_x + width : gif->width;
+ gif->height = (offset_y + height > gif->height) ?
+ offset_y + height : gif->height;
/* Decode the flags */
flags = gif_data[9];
@@ -898,6 +883,12 @@ gif_internal_decode_frame(gif_animation *gif,
goto gif_decode_frame_exit;
}
+ /* Make sure we have a buffer to decode to.
+ */
+ if (gif_initialise_sprite(gif, gif->width, gif->height)) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
/* Decode the flags */
flags = gif_data[9];
colour_table_size = 2 << (flags & GIF_COLOUR_TABLE_SIZE_MASK);
@@ -1223,14 +1214,6 @@ gif_result gif_initialise(gif_animation *gif, size_t
size, unsigned char *data)
}
gif->frame_holders = 1;
- /* Initialise the bitmap header */
- assert(gif->bitmap_callbacks.bitmap_create);
- gif->frame_image =
gif->bitmap_callbacks.bitmap_create(gif->width, gif->height);
- if (gif->frame_image == NULL) {
- gif_finalise(gif);
- return GIF_INSUFFICIENT_MEMORY;
- }
-
/* Remember we've done this now */
gif->buffer_position = gif_data - gif->gif_data;
}
diff --git a/test/decode_gif.c b/test/decode_gif.c
index 619be29..64387ef 100644
--- a/test/decode_gif.c
+++ b/test/decode_gif.c
@@ -161,6 +161,10 @@ static void write_ppm(FILE* fh, const char *name,
gif_animation *gif,
if (code != GIF_OK)
warning("gif_decode_frame", code);
+ if (!gif->frames[i].display) {
+ continue;
+ }
+
if (!no_write) {
fprintf(fh, "# frame %u:\n", i);
image = (unsigned char *) gif->frame_image;
--
NetSurf GIF Decoder
_______________________________________________
netsurf-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]