mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-26 05:31:02 +03:00 
			
		
		
		
	find * -type f "-(" -name "*.bdf" -o -name "*.c" -o -name "*.h" -o -name "*.py" -o -name "*.rst" -o -name "*.txt" "-)" -exec sed -e "s/[[:space:]]*$//" -i {} \;
		
	
			
		
			
				
	
	
		
			298 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			298 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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, 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;
 | |
| }
 |