Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Imaging/libImaging/GifDecode.c
diff options
context:
space:
mode:
Diffstat (limited to 'Imaging/libImaging/GifDecode.c')
-rw-r--r--Imaging/libImaging/GifDecode.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/Imaging/libImaging/GifDecode.c b/Imaging/libImaging/GifDecode.c
new file mode 100644
index 0000000..d97c276
--- /dev/null
+++ b/Imaging/libImaging/GifDecode.c
@@ -0,0 +1,297 @@
+/*
+ * The Python Imaging Library.
+ * $Id: GifDecode.c 2134 2004-10-06 08:55:20Z fredrik $
+ *
+ * a fast, suspendable GIF decoder
+ *
+ * history:
+ * 95-09-03 fl Created
+ * 95-09-05 fl Fixed sign problem on 16-bit platforms
+ * 95-09-13 fl Added some storage shortcuts
+ * 96-03-28 fl Revised API, integrated with PIL
+ * 96-12-10 fl Added interlace support
+ * 96-12-16 fl Fixed premature termination bug introduced by last fix
+ * 97-01-05 fl Don't mess up on bogus configuration
+ * 97-01-17 fl Don't mess up on very small, interlaced files
+ * 99-02-07 fl Minor speedups
+ *
+ * Copyright (c) Secret Labs AB 1997-99.
+ * Copyright (c) Fredrik Lundh 1995-97.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#include <stdio.h>
+#include <memory.h> /* memcpy() */
+
+#include "Gif.h"
+
+
+#define NEWLINE(state, context) {\
+ state->x = 0;\
+ state->y += context->step;\
+ while (state->y >= state->ysize)\
+ switch (context->interlace) {\
+ case 1:\
+ context->repeat = state->y = 4;\
+ context->interlace = 2;\
+ break;\
+ case 2:\
+ context->step = 4;\
+ context->repeat = state->y = 2;\
+ context->interlace = 3;\
+ break;\
+ case 3:\
+ context->step = 2;\
+ context->repeat = state->y = 1;\
+ context->interlace = 0;\
+ break;\
+ default:\
+ return -1;\
+ }\
+ if (state->y < state->ysize)\
+ out = im->image8[state->y + state->yoff] + state->xoff;\
+}
+
+
+int
+ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes)
+{
+ UINT8* p;
+ UINT8* out;
+ int c, i;
+ int thiscode;
+ GIFDECODERSTATE *context = (GIFDECODERSTATE*) state->context;
+
+ UINT8 *ptr = buffer;
+
+ if (!state->state) {
+
+ /* Initialise state */
+ if (context->bits < 0 || context->bits > 8) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ /* Clear code */
+ context->clear = 1 << context->bits;
+
+ /* End code */
+ context->end = context->clear + 1;
+
+ /* Interlace */
+ if (context->interlace) {
+ context->interlace = 1;
+ context->step = context->repeat = 8;
+ } else
+ context->step = 1;
+
+ state->state = 1;
+ }
+
+ out = im->image8[state->y + state->yoff] + state->xoff + state->x;
+
+ for (;;) {
+
+ if (state->state == 1) {
+
+ /* First free entry in table */
+ context->next = context->clear + 2;
+
+ /* Initial code size */
+ context->codesize = context->bits + 1;
+ context->codemask = (1 << context->codesize) - 1;
+
+ /* Buffer pointer. We fill the buffer from right, which
+ allows us to return all of it in one operation. */
+ context->bufferindex = GIFBUFFER;
+
+ state->state = 2;
+ }
+
+ if (context->bufferindex < GIFBUFFER) {
+
+ /* Return whole buffer in one chunk */
+ i = GIFBUFFER - context->bufferindex;
+ p = &context->buffer[context->bufferindex];
+
+ context->bufferindex = GIFBUFFER;
+
+ } else {
+
+ /* Get current symbol */
+
+ while (context->bitcount < context->codesize) {
+
+ if (context->blocksize > 0) {
+
+ /* Read next byte */
+ c = *ptr++; bytes--;
+
+ context->blocksize--;
+
+ /* New bits are shifted in from from the left. */
+ context->bitbuffer |= (INT32) c << context->bitcount;
+ context->bitcount += 8;
+
+ } else {
+
+ /* New GIF block */
+
+ /* We don't start decoding unless we have a full block */
+ if (bytes < 1)
+ return ptr - buffer;
+ c = *ptr;
+ if (bytes < c+1)
+ return ptr - buffer;
+
+ context->blocksize = c;
+
+ ptr++; bytes--;
+
+ }
+ }
+
+ /* Extract current symbol from bit buffer. */
+ c = (int) context->bitbuffer & context->codemask;
+
+ /* Adjust buffer */
+ context->bitbuffer >>= context->codesize;
+ context->bitcount -= context->codesize;
+
+ /* If c is less than "clear", it's a data byte. Otherwise,
+ it's either clear/end or a code symbol which should be
+ expanded. */
+
+ if (c == context->clear) {
+ if (state->state != 2)
+ state->state = 1;
+ continue;
+ }
+
+ if (c == context->end)
+ break;
+
+ i = 1;
+ p = &context->lastdata;
+
+ if (state->state == 2) {
+
+ /* First valid symbol after clear; use as is */
+ if (c > context->clear) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ context->lastdata = context->lastcode = c;
+ state->state = 3;
+
+ } else {
+
+ thiscode = c;
+
+ if (c > context->next) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ if (c == context->next) {
+
+ /* c == next is allowed. not sure why. */
+
+ if (context->bufferindex <= 0) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ context->buffer[--context->bufferindex] =
+ context->lastdata;
+
+ c = context->lastcode;
+
+ }
+
+ while (c >= context->clear) {
+
+ /* Copy data string to buffer (beginning from right) */
+
+ if (context->bufferindex <= 0 || c >= GIFTABLE) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ context->buffer[--context->bufferindex] =
+ context->data[c];
+
+ c = context->link[c];
+ }
+
+ context->lastdata = c;
+
+ if (context->next < GIFTABLE) {
+
+ /* We'll only add this symbol if we have room
+ for it (take advise, Netscape!) */
+ context->data[context->next] = c;
+ context->link[context->next] = context->lastcode;
+
+ if (context->next == context->codemask &&
+ context->codesize < GIFBITS) {
+
+ /* Expand code size */
+ context->codesize++;
+ context->codemask = (1 << context->codesize) - 1;
+ }
+
+ context->next++;
+
+ }
+
+ context->lastcode = thiscode;
+
+ }
+ }
+
+ /* Copy the bytes into the image */
+ if (state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ /* To squeeze some extra pixels out of this loop, we test for
+ some common cases and handle them separately. */
+
+ /* FIXME: should we handle the transparency index in here??? */
+
+ if (i == 1) {
+ if (state->x < state->xsize-1) {
+ /* Single pixel, not at the end of the line. */
+ *out++ = p[0];
+ state->x++;
+ continue;
+ }
+ } else if (state->x + i <= state->xsize) {
+ /* This string fits into current line. */
+ memcpy(out, p, i);
+ out += i;
+ state->x += i;
+ if (state->x == state->xsize) {
+ NEWLINE(state, context);
+ }
+ continue;
+ }
+
+ /* No shortcut, copy pixel by pixel */
+ for (c = 0; c < i; c++) {
+ *out++ = p[c];
+ if (++state->x >= state->xsize) {
+ NEWLINE(state, context);
+ }
+ }
+ }
+
+ return ptr - buffer;
+}