Pillow
285 строк · 9.4 Кб
1/*
2* The Python Imaging Library.
3* $Id$
4*
5* a fast, suspendable GIF decoder
6*
7* history:
8* 95-09-03 fl Created
9* 95-09-05 fl Fixed sign problem on 16-bit platforms
10* 95-09-13 fl Added some storage shortcuts
11* 96-03-28 fl Revised API, integrated with PIL
12* 96-12-10 fl Added interlace support
13* 96-12-16 fl Fixed premature termination bug introduced by last fix
14* 97-01-05 fl Don't mess up on bogus configuration
15* 97-01-17 fl Don't mess up on very small, interlaced files
16* 99-02-07 fl Minor speedups
17*
18* Copyright (c) Secret Labs AB 1997-99.
19* Copyright (c) Fredrik Lundh 1995-97.
20*
21* See the README file for information on usage and redistribution.
22*/
23
24#include "Imaging.h"25
26#include <stdio.h>27#include <memory.h> /* memcpy() */28
29#include "Gif.h"30
31#define NEWLINE(state, context) \32{ \33state->x = 0; \34state->y += context->step; \35while (state->y >= state->ysize) switch (context->interlace) { \36case 1: \37context->repeat = state->y = 4; \38context->interlace = 2; \39break; \40case 2: \41context->step = 4; \42context->repeat = state->y = 2; \43context->interlace = 3; \44break; \45case 3: \46context->step = 2; \47context->repeat = state->y = 1; \48context->interlace = 0; \49break; \50default: \51return -1; \52} \53if (state->y < state->ysize) { \54out = im->image8[state->y + state->yoff] + state->xoff; \55} \56}57
58int
59ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes) {60UINT8 *p;61UINT8 *out;62int c, i;63int thiscode;64GIFDECODERSTATE *context = (GIFDECODERSTATE *)state->context;65
66UINT8 *ptr = buffer;67
68if (!state->state) {69/* Initialise state */70if (context->bits < 0 || context->bits > 12) {71state->errcode = IMAGING_CODEC_CONFIG;72return -1;73}74
75/* Clear code */76context->clear = 1 << context->bits;77
78/* End code */79context->end = context->clear + 1;80
81/* Interlace */82if (context->interlace) {83context->interlace = 1;84context->step = context->repeat = 8;85} else {86context->step = 1;87}88
89state->state = 1;90}91
92out = im->image8[state->y + state->yoff] + state->xoff + state->x;93
94for (;;) {95if (state->state == 1) {96/* First free entry in table */97context->next = context->clear + 2;98
99/* Initial code size */100context->codesize = context->bits + 1;101context->codemask = (1 << context->codesize) - 1;102
103/* Buffer pointer. We fill the buffer from right, which104allows us to return all of it in one operation. */
105context->bufferindex = GIFBUFFER;106
107state->state = 2;108}109
110if (context->bufferindex < GIFBUFFER) {111/* Return whole buffer in one chunk */112i = GIFBUFFER - context->bufferindex;113p = &context->buffer[context->bufferindex];114
115context->bufferindex = GIFBUFFER;116
117} else {118/* Get current symbol */119
120while (context->bitcount < context->codesize) {121if (context->blocksize > 0) {122/* Read next byte */123c = *ptr++;124bytes--;125
126context->blocksize--;127
128/* New bits are shifted in from the left. */129context->bitbuffer |= (INT32)c << context->bitcount;130context->bitcount += 8;131
132} else {133/* New GIF block */134
135/* We don't start decoding unless we have a full block */136if (bytes < 1) {137return ptr - buffer;138}139c = *ptr;140if (bytes < c + 1) {141return ptr - buffer;142}143
144context->blocksize = c;145
146ptr++;147bytes--;148}149}150
151/* Extract current symbol from bit buffer. */152c = (int)context->bitbuffer & context->codemask;153
154/* Adjust buffer */155context->bitbuffer >>= context->codesize;156context->bitcount -= context->codesize;157
158/* If c is less than "clear", it's a data byte. Otherwise,159it's either clear/end or a code symbol which should be
160expanded. */
161
162if (c == context->clear) {163if (state->state != 2) {164state->state = 1;165}166continue;167}168
169if (c == context->end) {170break;171}172
173i = 1;174p = &context->lastdata;175
176if (state->state == 2) {177/* First valid symbol after clear; use as is */178if (c > context->clear) {179state->errcode = IMAGING_CODEC_BROKEN;180return -1;181}182
183context->lastdata = context->lastcode = c;184state->state = 3;185
186} else {187thiscode = c;188
189if (c > context->next) {190state->errcode = IMAGING_CODEC_BROKEN;191return -1;192}193
194if (c == context->next) {195/* c == next is allowed. not sure why. */196
197if (context->bufferindex <= 0) {198state->errcode = IMAGING_CODEC_BROKEN;199return -1;200}201
202context->buffer[--context->bufferindex] = context->lastdata;203
204c = context->lastcode;205}206
207while (c >= context->clear) {208/* Copy data string to buffer (beginning from right) */209
210if (context->bufferindex <= 0 || c >= GIFTABLE) {211state->errcode = IMAGING_CODEC_BROKEN;212return -1;213}214
215context->buffer[--context->bufferindex] = context->data[c];216
217c = context->link[c];218}219
220context->lastdata = c;221
222if (context->next < GIFTABLE) {223/* We'll only add this symbol if we have room224for it (take the advice, Netscape!) */
225context->data[context->next] = c;226context->link[context->next] = context->lastcode;227
228if (context->next == context->codemask &&229context->codesize < GIFBITS) {230/* Expand code size */231context->codesize++;232context->codemask = (1 << context->codesize) - 1;233}234
235context->next++;236}237
238context->lastcode = thiscode;239}240}241
242/* Copy the bytes into the image */243if (state->y >= state->ysize) {244state->errcode = IMAGING_CODEC_OVERRUN;245return -1;246}247
248/* To squeeze some extra pixels out of this loop, we test for249some common cases and handle them separately. */
250
251/* This cannot be used if there is transparency */252if (context->transparency == -1) {253if (i == 1) {254if (state->x < state->xsize - 1) {255/* Single pixel, not at the end of the line. */256*out++ = p[0];257state->x++;258continue;259}260} else if (state->x + i <= state->xsize) {261/* This string fits into current line. */262memcpy(out, p, i);263out += i;264state->x += i;265if (state->x == state->xsize) {266NEWLINE(state, context);267}268continue;269}270}271
272/* No shortcut, copy pixel by pixel */273for (c = 0; c < i; c++) {274if (p[c] != context->transparency) {275*out = p[c];276}277out++;278if (++state->x >= state->xsize) {279NEWLINE(state, context);280}281}282}283
284return ptr - buffer;285}
286