diff options
Diffstat (limited to 'generic/tkImgGIF.c')
-rw-r--r-- | generic/tkImgGIF.c | 307 |
1 files changed, 169 insertions, 138 deletions
diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c index 32c784e..473ed3c 100644 --- a/generic/tkImgGIF.c +++ b/generic/tkImgGIF.c @@ -13,8 +13,8 @@ * Copyright (c) 1997 Australian National University * Copyright (c) 2005 Donal K. Fellows * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. * * This file also contains code from the giftoppm program, which is * copyrighted as follows: @@ -32,9 +32,11 @@ * This file also contains code from miGIF. See lower down in file for the * applicable copyright notice for that portion. * - * RCS: @(#) $Id: tkImgGIF.c,v 1.37 2007/09/11 18:05:04 rmax Exp $ + * RCS: @(#) $Id: tkImgGIF.c,v 1.38 2007/09/18 12:37:13 dkf Exp $ */ +#include "tkInt.h" + /* * GIF's are represented as data in either binary or base64 format. base64 * strings consist of 4 6-bit characters -> 3 8 bit bytes. A-Z, a-z, 0-9, + @@ -61,8 +63,6 @@ typedef struct mFile { int length; /* Total amount of bytes in data */ } MFile; -#include "tkInt.h" - /* * Non-ASCII encoding support: * Most data in a GIF image is binary and is treated as such. However, a few @@ -73,16 +73,22 @@ typedef struct mFile { * independant. */ -static CONST char GIF87a[] = { /* ASCII GIF87a */ +static const char GIF87a[] = { /* ASCII GIF87a */ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x00 }; -static CONST char GIF89a[] = { /* ASCII GIF89a */ +static const char GIF89a[] = { /* ASCII GIF89a */ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x00 }; #define GIF_TERMINATOR 0x3b /* ASCII ; */ #define GIF_EXTENSION 0x21 /* ASCII ! */ #define GIF_START 0x2c /* ASCII , */ +/* + * Flags used to notify that we've got inline data instead of a file to read + * from. Note that we need to figure out which type of inline data we've got + * before handing off to the GIF reading code; this is done in StringReadGIF. + */ + #define INLINE_DATA_BINARY ((const char *) 0x01) #define INLINE_DATA_BASE64 ((const char *) 0x02) @@ -109,11 +115,11 @@ typedef struct { * The format record for the GIF file format: */ -static int FileMatchGIF(Tcl_Channel chan, CONST char *fileName, +static int FileMatchGIF(Tcl_Channel chan, const char *fileName, Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp); static int FileReadGIF(Tcl_Interp *interp, Tcl_Channel chan, - CONST char *fileName, Tcl_Obj *format, + const char *fileName, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY); static int StringMatchGIF(Tcl_Obj *dataObj, Tcl_Obj *format, @@ -122,7 +128,7 @@ static int StringReadGIF(Tcl_Interp *interp, Tcl_Obj *dataObj, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY); -static int FileWriteGIF(Tcl_Interp *interp, CONST char *filename, +static int FileWriteGIF(Tcl_Interp *interp, const char *filename, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr); static int CommonWriteGIF(Tcl_Interp *interp, Tcl_Channel handle, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr); @@ -165,11 +171,10 @@ static int ReadColorMap(GIFImageConfig *gifConfPtr, static int ReadGIFHeader(GIFImageConfig *gifConfPtr, Tcl_Channel chan, int *widthPtr, int *heightPtr); static int ReadImage(GIFImageConfig *gifConfPtr, - Tcl_Interp *interp, char *imagePtr, + Tcl_Interp *interp, unsigned char *imagePtr, Tcl_Channel chan, int len, int rows, - unsigned char cmap[MAXCOLORMAPSIZE][4], - int width, int height, int srcX, int srcY, - int interlace, int transparent); + unsigned char cmap[MAXCOLORMAPSIZE][4], int srcX, + int srcY, int interlace, int transparent); /* * these are for the BASE64 image reader code only @@ -205,7 +210,7 @@ static void mInit(unsigned char *string, MFile *handle, static int FileMatchGIF( Tcl_Channel chan, /* The image file, open for reading. */ - CONST char *fileName, /* The name of the image file. */ + const char *fileName, /* The name of the image file. */ Tcl_Obj *format, /* User-specified format object, or NULL. */ int *widthPtr, int *heightPtr, /* The dimensions of the image are returned @@ -241,7 +246,7 @@ static int FileReadGIF( Tcl_Interp *interp, /* Interpreter to use for reporting errors. */ Tcl_Channel chan, /* The image file, open for reading. */ - CONST char *fileName, /* The name of the image file. */ + const char *fileName, /* The name of the image file. */ Tcl_Obj *format, /* User-specified format object, or NULL. */ Tk_PhotoHandle imageHandle, /* The photo image to write into. */ int destX, int destY, /* Coordinates of top-left pixel in photo @@ -252,15 +257,14 @@ FileReadGIF( * image being read. */ { int fileWidth, fileHeight, imageWidth, imageHeight; - int nBytes, index = 0, argc = 0, i; + int nBytes, index = 0, argc = 0, i, result = TCL_ERROR; Tcl_Obj **objv; - Tk_PhotoImageBlock block; unsigned char buf[100]; unsigned char *trashBuffer = NULL; int bitPixel; unsigned char colorMap[MAXCOLORMAPSIZE][4]; int transparent = -1; - static CONST char *optionStrings[] = { + static const char *optionStrings[] = { "-index", NULL }; GIFImageConfig gifConf, *gifConfPtr = &gifConf; @@ -276,6 +280,10 @@ FileReadGIF( fileName = "inline data"; } + /* + * Parse the format string to get options. + */ + if (format && Tcl_ListObjGetElements(interp, format, &argc, &objv) != TCL_OK) { return TCL_ERROR; @@ -294,6 +302,11 @@ FileReadGIF( return TCL_ERROR; } } + + /* + * Read the GIF file header and check for some sanity. + */ + if (!ReadGIFHeader(gifConfPtr, chan, &fileWidth, &fileHeight)) { Tcl_AppendResult(interp, "couldn't read GIF header from file \"", fileName, "\"", NULL); @@ -305,10 +318,14 @@ FileReadGIF( return TCL_ERROR; } + /* + * Get the general colormap information. + */ + if (Fread(gifConfPtr, buf, 1, 3, chan) != 3) { return TCL_OK; } - bitPixel = 2<<(buf[0]&0x07); + bitPixel = 2 << (buf[0] & 0x07); if (BitSet(buf[0], LOCALCOLORMAP)) { /* Global Colormap */ if (!ReadColorMap(gifConfPtr, chan, bitPixel, colorMap)) { @@ -328,20 +345,19 @@ FileReadGIF( return TCL_OK; } + /* + * Make sure we have enough space in the photo image to hold the data from + * the GIF. + */ + if (Tk_PhotoExpand(interp, imageHandle, destX + width, destY + height) != TCL_OK) { return TCL_ERROR; } - block.width = width; - block.height = height; - block.pixelSize = 4; - block.pitch = block.pixelSize * block.width; - block.offset[0] = 0; - block.offset[1] = 1; - block.offset[2] = 2; - block.offset[3] = 3; - block.pixelPtr = NULL; + /* + * Search for the frame from the GIF to display. + */ while (1) { if (Fread(gifConfPtr, buf, 1, 1, chan) != 1) { @@ -354,16 +370,12 @@ FileReadGIF( goto error; } - if (buf[0] == GIF_TERMINATOR) { - /* - * GIF terminator. - */ - + switch (buf[0]) { + case GIF_TERMINATOR: Tcl_AppendResult(interp, "no image data for this index", NULL); goto error; - } - if (buf[0] == GIF_EXTENSION) { + case GIF_EXTENSION: /* * This is a GIF extension. */ @@ -381,9 +393,15 @@ FileReadGIF( goto error; } continue; - } - - if (buf[0] != GIF_START) { + case GIF_START: + if (Fread(gifConfPtr, buf, 1, 9, chan) != 9) { + Tcl_SetResult(interp, + "couldn't read left/top/width/height in GIF image", + TCL_STATIC); + goto error; + } + break; + default: /* * Not a valid start character; ignore it. */ @@ -391,21 +409,18 @@ FileReadGIF( continue; } - if (Fread(gifConfPtr, buf, 1, 9, chan) != 9) { - Tcl_SetResult(interp, - "couldn't read left/top/width/height in GIF image", - TCL_STATIC); - goto error; - } + /* + * We've read the header for a GIF frame. Work out what we are going + * to do about it. + */ imageWidth = LM_to_uint(buf[4], buf[5]); imageHeight = LM_to_uint(buf[6], buf[7]); - - bitPixel = 1<<((buf[8]&0x07)+1); + bitPixel = 1 << ((buf[8] & 0x07) + 1); if (index--) { /* - * This is not the image we want to read: skip it. + * This is not the GIF frame we want to read: skip it. */ if (BitSet(buf[8], LOCALCOLORMAP)) { @@ -421,7 +436,7 @@ FileReadGIF( if (trashBuffer == NULL) { nBytes = fileWidth * fileHeight * 3; - trashBuffer = (unsigned char *) ckalloc((unsigned int) nBytes); + trashBuffer = (unsigned char *) ckalloc((unsigned) nBytes); } /* @@ -441,81 +456,93 @@ FileReadGIF( * common case. */ - if (ReadImage(gifConfPtr, interp, (char *)trashBuffer, chan, - imageWidth, imageHeight, colorMap, 0, 0, 0, 0, 0, - -1) != TCL_OK) { + if (ReadImage(gifConfPtr, interp, trashBuffer, chan, imageWidth, + imageHeight, colorMap, 0, 0, 0, -1) != TCL_OK) { goto error; } continue; } + break; + } - if (BitSet(buf[8], LOCALCOLORMAP)) { - if (!ReadColorMap(gifConfPtr, chan, bitPixel, colorMap)) { - Tcl_AppendResult(interp, "error reading color map", NULL); - goto error; - } - } + /* + * Found the frame we want to read. Next, check for a local color map for + * this frame. + */ - index = LM_to_uint(buf[0], buf[1]); - srcX -= index; - if (srcX<0) { - destX -= srcX; width += srcX; - srcX = 0; + if (BitSet(buf[8], LOCALCOLORMAP)) { + if (!ReadColorMap(gifConfPtr, chan, bitPixel, colorMap)) { + Tcl_AppendResult(interp, "error reading color map", NULL); + goto error; } + } - if (width > imageWidth) { - width = imageWidth; - } + /* + * Extract the location within the overall visible image to put the data + * in this frame, together with the size of this frame. + */ - index = LM_to_uint(buf[2], buf[3]); - srcY -= index; - if (index > srcY) { - destY -= srcY; height += srcY; - srcY = 0; - } - if (height > imageHeight) { - height = imageHeight; - } + index = LM_to_uint(buf[0], buf[1]); + srcX -= index; + if (srcX<0) { + destX -= srcX; width += srcX; + srcX = 0; + } - if ((width <= 0) || (height <= 0)) { - block.pixelPtr = 0; - goto noerror; - } + if (width > imageWidth) { + width = imageWidth; + } + + index = LM_to_uint(buf[2], buf[3]); + srcY -= index; + if (index > srcY) { + destY -= srcY; height += srcY; + srcY = 0; + } + if (height > imageHeight) { + height = imageHeight; + } + + if ((width > 0) && (height > 0)) { + Tk_PhotoImageBlock block; + + /* + * Read the data and put it into the photo buffer for display by the + * general image machinery. + */ block.width = width; block.height = height; block.pixelSize = (transparent>=0) ? 4 : 3; + block.offset[0] = 0; + block.offset[1] = 1; + block.offset[2] = 2; block.offset[3] = (transparent>=0) ? 3 : 0; block.pitch = block.pixelSize * imageWidth; nBytes = block.pitch * imageHeight; block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes); - if (ReadImage(gifConfPtr, interp, (char *) block.pixelPtr, chan, - imageWidth,imageHeight, colorMap, fileWidth,fileHeight, - srcX,srcY, BitSet(buf[8],INTERLACE), transparent) != TCL_OK) { + if (ReadImage(gifConfPtr, interp, block.pixelPtr, chan, imageWidth, + imageHeight, colorMap, srcX, srcY, BitSet(buf[8],INTERLACE), + transparent) != TCL_OK) { + ckfree((char *) block.pixelPtr); goto error; } - break; - } - - if (Tk_PhotoPutBlock(interp, imageHandle, &block, destX, destY, - width, height, TK_PHOTO_COMPOSITE_SET) != TCL_OK) { - goto error; + if (Tk_PhotoPutBlock(interp, imageHandle, &block, destX, destY, + width, height, TK_PHOTO_COMPOSITE_SET) != TCL_OK) { + ckfree((char *) block.pixelPtr); + goto error; + } + ckfree((char *) block.pixelPtr); } - noerror: /* - * If a trash buffer has been allocated, free it now. + * We've successfully read the GIF frame (or there was nothing to read, + * which suits as well). We're done. */ - if (trashBuffer != NULL) { - ckfree((char *)trashBuffer); - } - if (block.pixelPtr) { - ckfree((char *) block.pixelPtr); - } Tcl_AppendResult(interp, tkImgFmtGIF.name, NULL); - return TCL_OK; + result = TCL_OK; error: /* @@ -523,12 +550,9 @@ FileReadGIF( */ if (trashBuffer != NULL) { - ckfree((char *)trashBuffer); + ckfree((char *) trashBuffer); } - if (block.pixelPtr) { - ckfree((char *) block.pixelPtr); - } - return TCL_ERROR; + return result; } /* @@ -589,7 +613,7 @@ StringMatchGIF( return 0; } } else { - memcpy((void *) header, (void *) data, 10); + memcpy(header, data, 10); } *widthPtr = LM_to_uint(header[6], header[7]); *heightPtr = LM_to_uint(header[8], header[9]); @@ -628,24 +652,32 @@ StringReadGIF( { MFile handle, *hdlPtr = &handle; int length; - char *data = (char *) Tcl_GetByteArrayFromObj(dataObj, &length); + const char *xferFormat; + unsigned char *data = Tcl_GetByteArrayFromObj(dataObj, &length); - mInit((unsigned char *)data, hdlPtr, length); + mInit(data, hdlPtr, length); - if (strncmp(GIF87a, data, 6) && strncmp(GIF89a, data, 6)) { - /* - * Check whether the data is Base64 encoded by doing a - * character-by-charcter comparison with the binary-format headers; - * BASE64-encoded never matches (matching the other way is harder - * because of potential padding). - */ + /* + * Check whether the data is Base64 encoded by doing a character-by- + * charcter comparison with the binary-format headers; BASE64-encoded + * never matches (matching the other way is harder because of potential + * padding of the BASE64 data). + */ - return FileReadGIF(interp, (Tcl_Channel) hdlPtr, INLINE_DATA_BASE64, - format, imageHandle, destX, destY, width, height, srcX, srcY); + if (strncmp(GIF87a, (unsigned char *) data, 6) + && strncmp(GIF89a, (unsigned char *) data, 6)) { + xferFormat = INLINE_DATA_BASE64; } else { - return FileReadGIF(interp, (Tcl_Channel) hdlPtr, INLINE_DATA_BINARY, - format, imageHandle, destX, destY, width, height, srcX, srcY); + xferFormat = INLINE_DATA_BINARY; } + + /* + * Fall through to the file reader now that we have a correctly-configured + * pseudo-channel to pull the data from. + */ + + return FileReadGIF(interp, (Tcl_Channel) hdlPtr, xferFormat, format, + imageHandle, destX, destY, width, height, srcX, srcY); } /* @@ -694,8 +726,8 @@ ReadGIFHeader( /* *----------------------------------------------------------------- - * The code below is copied from the giftoppm program and modified - * just slightly. + * The code below is copied from the giftoppm program and modified just + * slightly. *----------------------------------------------------------------- */ @@ -818,20 +850,19 @@ static int ReadImage( GIFImageConfig *gifConfPtr, Tcl_Interp *interp, - char *imagePtr, + unsigned char *imagePtr, Tcl_Channel chan, int len, int rows, unsigned char cmap[MAXCOLORMAPSIZE][4], - int width, int height, int srcX, int srcY, int interlace, int transparent) { unsigned char initialCodeSize; int xpos = 0, ypos = 0, pass = 0, i; - register char *pixelPtr; - static CONST int interlaceStep[] = { 8, 8, 4, 2 }; - static CONST int interlaceStart[] = { 0, 4, 2, 1 }; + register unsigned char *pixelPtr; + static const int interlaceStep[] = { 8, 8, 4, 2 }; + static const int interlaceStart[] = { 0, 4, 2, 1 }; unsigned short prefix[(1 << MAX_LWZ_BITS)]; unsigned char append[(1 << MAX_LWZ_BITS)]; unsigned char stack[(1 << MAX_LWZ_BITS)*2]; @@ -874,8 +905,8 @@ ReadImage( oldCode = -1; firstCode = -1; - memset((void *)prefix, 0, (1 << MAX_LWZ_BITS) * sizeof(short)); - memset((void *)append, 0, (1 << MAX_LWZ_BITS) * sizeof(char)); + memset(prefix, 0, (1 << MAX_LWZ_BITS) * sizeof(short)); + memset(append, 0, (1 << MAX_LWZ_BITS) * sizeof(char)); for (i = 0; i < clearCode; i++) { append[i] = i; } @@ -1346,18 +1377,17 @@ Fread( size_t hunk, size_t count, /* how many */ Tcl_Channel chan) { - MFile *handle; - if (gifConfPtr->fromData == INLINE_DATA_BASE64) { return Mread(dst, hunk, count, (MFile *) chan); } if (gifConfPtr->fromData == INLINE_DATA_BINARY) { - handle = (MFile *) chan; - if (handle->length <= 0 || (size_t)handle->length < hunk*count) { + MFile *handle = (MFile *) chan; + + if (handle->length <= 0 || (size_t) handle->length < hunk*count) { return -1; } - memcpy((void *)dst, (void *) handle->data, (size_t) (hunk * count)); + memcpy(dst, handle->data, (size_t) (hunk * count)); handle->data += hunk * count; return (int)(hunk * count); } @@ -1442,7 +1472,7 @@ static int ReadValue(ClientData clientData); static int FileWriteGIF( Tcl_Interp *interp, /* Interpreter to use for reporting errors. */ - CONST char *filename, + const char *filename, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr) { @@ -1612,8 +1642,9 @@ color( int red, int green, int blue, unsigned char mapa[MAXCOLORMAPSIZE][3]) { - int x; - for (x=(statePtr->alphaOffset != 0) ; x<=MAXCOLORMAPSIZE ; x++) { + int x = (statePtr->alphaOffset != 0); + + for (; x<=MAXCOLORMAPSIZE ; x++) { if ((mapa[x][CM_RED] == red) && (mapa[x][CM_GREEN] == green) && (mapa[x][CM_BLUE] == blue)) { return x; @@ -1629,6 +1660,7 @@ nuevo( unsigned char mapa[MAXCOLORMAPSIZE][3]) { int x = (statePtr->alphaOffset != 0); + for (; x<=statePtr->num ; x++) { if ((mapa[x][CM_RED] == red) && (mapa[x][CM_GREEN] == green) && (mapa[x][CM_BLUE] == blue)) { @@ -1657,9 +1689,9 @@ savemap( statePtr->num = -1; } - for(y=0 ; y<blockPtr->height ; y++) { + for (y=0 ; y<blockPtr->height ; y++) { colores = blockPtr->pixelPtr + blockPtr->offset[0] + y*blockPtr->pitch; - for(x=0 ; x<blockPtr->width ; x++) { + for (x=0 ; x<blockPtr->width ; x++) { if (!statePtr->alphaOffset || colores[statePtr->alphaOffset]!=0) { red = colores[0]; green = colores[statePtr->greenOffset]; @@ -1677,7 +1709,6 @@ savemap( colores += statePtr->pixelSize; } } - return; } static int @@ -1972,8 +2003,8 @@ computeTriangleCount( count -= perrep; } if (count > 0) { - unsigned int n; - n = isqrt(count); + unsigned int n = isqrt(count); + while (n*(n+1) >= 2*count) { n--; } |