123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /*
- * The Python Imaging Library.
- * $Id$
- *
- * 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, Py_ssize_t 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 > 12) {
- 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 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 the advice, 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. */
- /* This cannot be used if there is transparency */
- if (context->transparency == -1) {
- 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++) {
- if (p[c] != context->transparency) {
- *out = p[c];
- }
- out++;
- if (++state->x >= state->xsize) {
- NEWLINE(state, context);
- }
- }
- }
- return ptr - buffer;
- }
|