summaryrefslogtreecommitdiffstats
path: root/generic/tkImgGIF.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tkImgGIF.c')
-rw-r--r--generic/tkImgGIF.c1380
1 files changed, 723 insertions, 657 deletions
diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c
index 6fe8627..9d11631 100644
--- a/generic/tkImgGIF.c
+++ b/generic/tkImgGIF.c
@@ -1,17 +1,17 @@
/*
* tkImgGIF.c --
*
- * A photo image file handler for GIF files. Reads 87a and 89a GIF
- * files. At present, there only is a file write function. GIF images
- * may be read using the -data option of the photo image. The data may be
- * given as a binary string in a Tcl_Obj or by representing
- * the data as BASE64 encoded ascii. Derived from the giftoppm code
- * found in the pbmplus package and tkImgFmtPPM.c in the tk4.0b2
- * distribution.
+ * A photo image file handler for GIF files. Reads 87a and 89a GIF files.
+ * At present, there only is a file write function. GIF images may be
+ * read using the -data option of the photo image. The data may be given
+ * as a binary string in a Tcl_Obj or by representing the data as BASE64
+ * encoded ascii. Derived from the giftoppm code found in the pbmplus
+ * package and tkImgFmtPPM.c in the tk4.0b2 distribution.
*
* Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
* 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.
@@ -27,18 +27,20 @@
* | copies and that both that copyright notice and this permission |
* | notice appear in supporting documentation. This software is |
* | provided "as is" without express or implied warranty. |
- * +-------------------------------------------------------------------+
+ * +--------------------------------------------------------------------+
+ *
+ * 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.26 2004/07/27 21:19:32 das Exp $
+ * RCS: @(#) $Id: tkImgGIF.c,v 1.27 2005/06/19 21:49:08 dkf Exp $
*/
/*
- * GIF's are represented as data in base64 format.
- * base64 strings consist of 4 6-bit characters -> 3 8 bit bytes.
- * A-Z, a-z, 0-9, + and / represent the 64 values (in order).
- * '=' is a trailing padding char when the un-encoded data is not a
- * multiple of 3 bytes. We'll ignore white space when encountered.
- * Any other invalid character is treated as an EOF
+ * 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, +
+ * and / represent the 64 values (in order). '=' is a trailing padding char
+ * when the un-encoded data is not a multiple of 3 bytes. We'll ignore white
+ * space when encountered. Any other invalid character is treated as an EOF
*/
#define GIF_SPECIAL (256)
@@ -48,15 +50,15 @@
#define GIF_DONE (GIF_SPECIAL+4)
/*
- * structure to "mimic" FILE for Mread, so we can look like fread.
- * The decoder state keeps track of which byte we are about to read,
- * or EOF.
+ * structure to "mimic" FILE for Mread, so we can look like fread. The
+ * decoder state keeps track of which byte we are about to read, or EOF.
*/
typedef struct mFile {
unsigned char *data; /* mmencoded source string */
int c; /* bits left over from previous character */
int state; /* decoder state (0-4 or GIF_DONE) */
+ int length; /* Total amount of bytes in data */
} MFile;
#include "tkInt.h"
@@ -64,12 +66,12 @@ typedef struct mFile {
/*
* Non-ASCII encoding support:
- * Most data in a GIF image is binary and is treated as such. However,
- * a few key bits are stashed in ASCII. If we try to compare those pieces
- * to the char they represent, it will fail on any non-ASCII (eg, EBCDIC)
- * system. To accomodate these systems, we test against the numeric value
- * of the ASCII characters instead of the characters themselves. This is
- * encoding independant.
+ * Most data in a GIF image is binary and is treated as such. However, a few
+ * key bits are stashed in ASCII. If we try to compare those pieces to the
+ * char they represent, it will fail on any non-ASCII (eg, EBCDIC) system. To
+ * accomodate these systems, we test against the numeric value of the ASCII
+ * characters instead of the characters themselves. This is encoding
+ * independant.
*/
static CONST char GIF87a[] = { /* ASCII GIF87a */
@@ -78,21 +80,31 @@ static CONST char GIF87a[] = { /* ASCII GIF87a */
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 , */
+#define GIF_TERMINATOR 0x3b /* ASCII ; */
+#define GIF_EXTENSION 0x21 /* ASCII ! */
+#define GIF_START 0x2c /* ASCII , */
+
+#define INLINE_DATA_BINARY ((const char *) 0x01)
+#define INLINE_DATA_BASE64 ((const char *) 0x02)
/*
- * HACK ALERT!! HACK ALERT!! HACK ALERT!!
- * This code is hard-wired for reading from files. In order to read
- * from a data stream, we'll trick fread so we can reuse the same code.
- * 0==from file; 1==from base64 encoded data; 2==from binary data
+ * HACK ALERT!! HACK ALERT!! HACK ALERT!!
+ * This code is hard-wired for reading from files. In order to read from a
+ * data stream, we'll trick fread so we can reuse the same code. 0==from file;
+ * 1==from base64 encoded data; 2==from binary data
*/
-typedef struct ThreadSpecificData {
- int fromData;
-} ThreadSpecificData;
-static Tcl_ThreadDataKey dataKey;
+typedef struct {
+ const char *fromData;
+ unsigned char workingBuffer[280];
+ struct {
+ int bytes;
+ int done;
+ unsigned int window;
+ int bitsInWindow;
+ unsigned char *c;
+ } reader;
+} GIFImageConfig;
/*
* The format record for the GIF file format:
@@ -101,18 +113,17 @@ static Tcl_ThreadDataKey dataKey;
static int FileMatchGIF _ANSI_ARGS_((Tcl_Channel chan, CONST char *fileName,
Tcl_Obj *format, int *widthPtr, int *heightPtr,
Tcl_Interp *interp));
-static int FileReadGIF _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format,
+static int FileReadGIF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan,
+ CONST char *fileName, Tcl_Obj *format,
Tk_PhotoHandle imageHandle, int destX, int destY,
int width, int height, int srcX, int srcY));
-static int StringMatchGIF _ANSI_ARGS_(( Tcl_Obj *dataObj,
- Tcl_Obj *format, int *widthPtr, int *heightPtr,
- Tcl_Interp *interp));
+static int StringMatchGIF _ANSI_ARGS_(( Tcl_Obj *dataObj, Tcl_Obj *format,
+ int *widthPtr, int *heightPtr, Tcl_Interp *interp));
static int StringReadGIF _ANSI_ARGS_((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 _ANSI_ARGS_((Tcl_Interp *interp,
+static int FileWriteGIF _ANSI_ARGS_((Tcl_Interp *interp,
CONST char *filename, Tcl_Obj *format,
Tk_PhotoImageBlock *blockPtr));
static int CommonWriteGIF _ANSI_ARGS_((Tcl_Interp *interp,
@@ -139,54 +150,54 @@ Tk_PhotoImageFormat tkImgFmtGIF = {
#define CM_ALPHA 3
#define MAX_LWZ_BITS 12
#define LM_to_uint(a,b) (((b)<<8)|(a))
-#define ReadOK(file,buffer,len) (Fread(buffer, len, 1, file) != 0)
/*
* Prototypes for local procedures defined in this file:
*/
-static int DoExtension _ANSI_ARGS_((Tcl_Channel chan, int label,
- int *transparent));
-static int GetCode _ANSI_ARGS_((Tcl_Channel chan, int code_size,
- int flag));
-static int GetDataBlock _ANSI_ARGS_((Tcl_Channel chan,
- unsigned char *buf));
-static int ReadColorMap _ANSI_ARGS_((Tcl_Channel chan, int number,
- unsigned char buffer[MAXCOLORMAPSIZE][4]));
-static int ReadGIFHeader _ANSI_ARGS_((Tcl_Channel chan,
- int *widthPtr, int *heightPtr));
-static int ReadImage _ANSI_ARGS_((Tcl_Interp *interp,
- 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));
+static int DoExtension _ANSI_ARGS_((GIFImageConfig *gifConfPtr,
+ Tcl_Channel chan, int label, unsigned char *buffer,
+ int *transparent));
+static int GetCode _ANSI_ARGS_((Tcl_Channel chan, int code_size, int flag,
+ GIFImageConfig *gifConfPtr));
+static int GetDataBlock _ANSI_ARGS_((GIFImageConfig *gifConfPtr,
+ Tcl_Channel chan, unsigned char *buf));
+static int ReadColorMap _ANSI_ARGS_((GIFImageConfig *gifConfPtr,
+ Tcl_Channel chan, int number,
+ unsigned char buffer[MAXCOLORMAPSIZE][4]));
+static int ReadGIFHeader _ANSI_ARGS_((GIFImageConfig *gifConfPtr,
+ Tcl_Channel chan, int *widthPtr, int *heightPtr));
+static int ReadImage _ANSI_ARGS_((GIFImageConfig *gifConfPtr,
+ Tcl_Interp *interp, 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));
/*
* these are for the BASE64 image reader code only
*/
-static int Fread _ANSI_ARGS_((unsigned char *dst, size_t size,
- size_t count, Tcl_Channel chan));
-static int Mread _ANSI_ARGS_((unsigned char *dst, size_t size,
- size_t count, MFile *handle));
-static int Mgetc _ANSI_ARGS_((MFile *handle));
-static int char64 _ANSI_ARGS_((int c));
-static void mInit _ANSI_ARGS_((unsigned char *string,
- MFile *handle));
-
+static int Fread _ANSI_ARGS_((GIFImageConfig *gifConfPtr,
+ unsigned char *dst, size_t size, size_t count,
+ Tcl_Channel chan));
+static int Mread _ANSI_ARGS_((unsigned char *dst, size_t size,
+ size_t count, MFile *handle));
+static int Mgetc _ANSI_ARGS_((MFile *handle));
+static int char64 _ANSI_ARGS_((int c));
+static void mInit _ANSI_ARGS_((unsigned char *string, MFile *handle,
+ int length));
/*
*----------------------------------------------------------------------
*
* FileMatchGIF --
*
- * This procedure is invoked by the photo image type to see if
- * a file contains image data in GIF format.
+ * This procedure is invoked by the photo image type to see if a file
+ * contains image data in GIF format.
*
* Results:
- * The return value is 1 if the first characters in file f look
- * like GIF data, and 0 otherwise.
+ * The return value is 1 if the first characters in file f look like GIF
+ * data, and 0 otherwise.
*
* Side effects:
* The access position in f may change.
@@ -199,12 +210,14 @@ FileMatchGIF(chan, fileName, format, widthPtr, heightPtr, interp)
Tcl_Channel chan; /* The image file, open for reading. */
CONST char *fileName; /* The name of the image file. */
Tcl_Obj *format; /* User-specified format object, or NULL. */
- int *widthPtr, *heightPtr; /* The dimensions of the image are
- * returned here if the file is a valid
- * raw GIF file. */
+ int *widthPtr, *heightPtr; /* The dimensions of the image are returned
+ * here if the file is a valid raw GIF file. */
Tcl_Interp *interp; /* not used */
{
- return ReadGIFHeader(chan, widthPtr, heightPtr);
+ GIFImageConfig gifConf;
+
+ memset(&gifConf, 0, sizeof(GIFImageConfig));
+ return ReadGIFHeader(&gifConf, chan, widthPtr, heightPtr);
}
/*
@@ -212,17 +225,16 @@ FileMatchGIF(chan, fileName, format, widthPtr, heightPtr, interp)
*
* FileReadGIF --
*
- * This procedure is called by the photo image type to read
- * GIF format data from a file and write it into a given
- * photo image.
+ * This procedure is called by the photo image type to read GIF format
+ * data from a file and write it into a given photo image.
*
* Results:
- * A standard TCL completion code. If TCL_ERROR is returned
- * then an error message is left in the interp's result.
+ * A standard TCL completion code. If TCL_ERROR is returned then an
+ * error message is left in the interp's result.
*
* Side effects:
- * The access position in file f is changed, and new data is
- * added to the image given by imageHandle.
+ * The access position in file f is changed, and new data is added to the
+ * image given by imageHandle.
*
*----------------------------------------------------------------------
*/
@@ -235,12 +247,12 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
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, destY; /* Coordinates of top-left pixel in
- * photo image to be written to. */
- int width, height; /* Dimensions of block of photo image to
- * be written to. */
- int srcX, srcY; /* Coordinates of top-left pixel to be used
- * in image being read. */
+ int destX, destY; /* Coordinates of top-left pixel in photo
+ * image to be written to. */
+ int width, height; /* Dimensions of block of photo image to be
+ * written to. */
+ int srcX, srcY; /* Coordinates of top-left pixel to be used in
+ * image being read. */
{
int fileWidth, fileHeight;
int nBytes, index = 0, argc = 0, i;
@@ -254,27 +266,38 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
static CONST char *optionStrings[] = {
"-index", NULL
};
+ GIFImageConfig gifConf, *gifConfPtr = &gifConf;
+
+ /*
+ * Decode the magic used to convey when we're sourcing data from a string
+ * source and not a file.
+ */
+
+ memset(gifConfPtr, 0, sizeof(GIFImageConfig));
+ if (fileName == INLINE_DATA_BINARY || fileName == INLINE_DATA_BASE64) {
+ gifConfPtr->fromData = fileName;
+ fileName = "inline data";
+ }
if (format && Tcl_ListObjGetElements(interp, format,
&argc, &objv) != TCL_OK) {
return TCL_ERROR;
}
for (i = 1; i < argc; i++) {
- if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option name", 0,
- &nBytes) != TCL_OK) {
+ if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option name",
+ 0, &nBytes) != TCL_OK) {
return TCL_ERROR;
}
if (i == (argc-1)) {
Tcl_AppendResult(interp, "no value given for \"",
- Tcl_GetStringFromObj(objv[i], NULL),
- "\" option", (char *) NULL);
+ Tcl_GetString(objv[i]), "\" option", (char *) NULL);
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[++i], &index) != TCL_OK) {
return TCL_ERROR;
}
}
- if (!ReadGIFHeader(chan, &fileWidth, &fileHeight)) {
+ if (!ReadGIFHeader(gifConfPtr, chan, &fileWidth, &fileHeight)) {
Tcl_AppendResult(interp, "couldn't read GIF header from file \"",
fileName, "\"", NULL);
return TCL_ERROR;
@@ -285,13 +308,13 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
return TCL_ERROR;
}
- if (Fread(buf, 1, 3, chan) != 3) {
+ if (Fread(gifConfPtr, buf, 1, 3, chan) != 3) {
return TCL_OK;
}
bitPixel = 2<<(buf[0]&0x07);
if (BitSet(buf[0], LOCALCOLORMAP)) { /* Global Colormap */
- if (!ReadColorMap(chan, bitPixel, colorMap)) {
+ if (!ReadColorMap(gifConfPtr, chan, bitPixel, colorMap)) {
Tcl_AppendResult(interp, "error reading color map",
(char *) NULL);
return TCL_ERROR;
@@ -325,13 +348,14 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
block.pixelPtr = NULL;
while (1) {
- if (Fread(buf, 1, 1, chan) != 1) {
+ if (Fread(gifConfPtr, buf, 1, 1, chan) != 1) {
/*
* Premature end of image.
*/
- Tcl_AppendResult(interp,"premature end of image data for this index",
- (char *) NULL);
+ Tcl_AppendResult(interp,
+ "premature end of image data for this index",
+ (char *) NULL);
goto error;
}
@@ -340,7 +364,7 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
* GIF terminator.
*/
- Tcl_AppendResult(interp,"no image data for this index",
+ Tcl_AppendResult(interp, "no image data for this index",
(char *) NULL);
goto error;
}
@@ -350,13 +374,14 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
* This is a GIF extension.
*/
- if (Fread(buf, 1, 1, chan) != 1) {
+ if (Fread(gifConfPtr, buf, 1, 1, chan) != 1) {
Tcl_SetResult(interp,
"error reading extension function code in GIF image",
TCL_STATIC);
goto error;
}
- if (DoExtension(chan, buf[0], &transparent) < 0) {
+ if (DoExtension(gifConfPtr, chan, buf[0],
+ gifConfPtr->workingBuffer, &transparent) < 0) {
Tcl_SetResult(interp, "error reading extension in GIF image",
TCL_STATIC);
goto error;
@@ -371,15 +396,15 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
continue;
}
- if (Fread(buf, 1, 9, chan) != 9) {
+ 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;
}
- fileWidth = LM_to_uint(buf[4],buf[5]);
- fileHeight = LM_to_uint(buf[6],buf[7]);
+ fileWidth = LM_to_uint(buf[4], buf[5]);
+ fileHeight = LM_to_uint(buf[6], buf[7]);
bitPixel = 1<<((buf[8]&0x07)+1);
@@ -388,7 +413,7 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
* This is not the image we want to read: skip it.
*/
if (BitSet(buf[8], LOCALCOLORMAP)) {
- if (!ReadColorMap(chan, bitPixel, colorMap)) {
+ if (!ReadColorMap(gifConfPtr, chan, bitPixel, colorMap)) {
Tcl_AppendResult(interp,
"error reading color map", (char *) NULL);
goto error;
@@ -400,43 +425,43 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
*/
if (trashBuffer == NULL) {
nBytes = fileWidth * fileHeight * 3;
- trashBuffer =
- (unsigned char *) ckalloc((unsigned int) nBytes);
+ trashBuffer = (unsigned char *) ckalloc((unsigned int) nBytes);
}
/*
- * Slurp! Process the data for this image and stuff it in
- * a trash buffer.
+ * Slurp! Process the data for this image and stuff it in a trash
+ * buffer.
*
- * Yes, it might be more efficient here to *not* store the
- * data (we're just going to throw it away later).
- * However, I elected to implement it this way for good
- * reasons. First, I wanted to avoid duplicating the
- * (fairly complex) LWZ decoder in ReadImage. Fine, you
- * say, why didn't you just modify it to allow the use of
- * a NULL specifier for the output buffer? I tried that,
- * but it negatively impacted the performance of what I
- * think will be the common case: reading the first image
- * in the file. Rather than marginally improve the speed
- * of the less frequent case, I chose to maintain high
- * performance for the common case.
+ * Yes, it might be more efficient here to *not* store the data
+ * (we're just going to throw it away later). However, I elected
+ * to implement it this way for good reasons. First, I wanted to
+ * avoid duplicating the (fairly complex) LWZ decoder in
+ * ReadImage. Fine, you say, why didn't you just modify it to
+ * allow the use of a NULL specifier for the output buffer? I
+ * tried that, but it negatively impacted the performance of what
+ * I think will be the common case: reading the first image in the
+ * file. Rather than marginally improve the speed of the less
+ * frequent case, I chose to maintain high performance for the
+ * common case.
*/
- if (ReadImage(interp, (char *) trashBuffer, chan, fileWidth,
- fileHeight, colorMap, 0, 0, 0, 0, 0, -1) != TCL_OK) {
+
+ if (ReadImage(gifConfPtr, interp, (char *)trashBuffer, chan,
+ fileWidth, fileHeight, colorMap, 0, 0, 0, 0, 0,
+ -1) != TCL_OK) {
goto error;
}
continue;
}
if (BitSet(buf[8], LOCALCOLORMAP)) {
- if (!ReadColorMap(chan, bitPixel, colorMap)) {
+ if (!ReadColorMap(gifConfPtr, chan, bitPixel, colorMap)) {
Tcl_AppendResult(interp, "error reading color map",
(char *) NULL);
goto error;
}
}
- index = LM_to_uint(buf[0],buf[1]);
+ index = LM_to_uint(buf[0], buf[1]);
srcX -= index;
if (srcX<0) {
destX -= srcX; width += srcX;
@@ -447,7 +472,7 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
width = fileWidth;
}
- index = LM_to_uint(buf[2],buf[3]);
+ index = LM_to_uint(buf[2], buf[3]);
srcY -= index;
if (index > srcY) {
destY -= srcY; height += srcY;
@@ -470,9 +495,9 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
nBytes = block.pitch * fileHeight;
block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
- if (ReadImage(interp, (char *) block.pixelPtr, chan, fileWidth,
- fileHeight, colorMap, fileWidth, fileHeight, srcX, srcY,
- BitSet(buf[8], INTERLACE), transparent) != TCL_OK) {
+ if (ReadImage(gifConfPtr, interp, (char *) block.pixelPtr, chan,
+ fileWidth, fileHeight, colorMap, fileWidth, fileHeight, srcX,
+ srcY, BitSet(buf[8], INTERLACE), transparent) != TCL_OK) {
goto error;
}
break;
@@ -483,7 +508,7 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
goto error;
}
- noerror:
+ noerror:
/*
* If a trash buffer has been allocated, free it now.
*/
@@ -496,7 +521,7 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
Tcl_AppendResult(interp, tkImgFmtGIF.name, (char *) NULL);
return TCL_OK;
- error:
+ error:
/*
* If a trash buffer has been allocated, free it now.
*/
@@ -514,15 +539,15 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
*
* StringMatchGIF --
*
- * This procedure is invoked by the photo image type to see if
- * an object contains image data in GIF format.
+ * This procedure is invoked by the photo image type to see if an object
+ * contains image data in GIF format.
*
* Results:
- * The return value is 1 if the first characters in the data are
- * like GIF data, and 0 otherwise.
+ * The return value is 1 if the first characters in the data are like GIF
+ * data, and 0 otherwise.
*
* Side effects:
- * the size of the image is placed in widthPre and heightPtr.
+ * The size of the image is placed in widthPtr and heightPtr.
*
*----------------------------------------------------------------------
*/
@@ -557,7 +582,7 @@ StringMatchGIF(dataObj, format, widthPtr, heightPtr, interp)
/*
* Try interpreting the data as Base64 encoded
*/
- mInit((unsigned char *) data, &handle);
+ mInit((unsigned char *) data, &handle, length);
got = Mread(header, 10, 1, &handle);
if (got != 10
|| ((strncmp(GIF87a, (char *) header, 6) != 0)
@@ -567,28 +592,27 @@ StringMatchGIF(dataObj, format, widthPtr, heightPtr, interp)
} else {
memcpy((VOID *) header, (VOID *) data, 10);
}
- *widthPtr = LM_to_uint(header[6],header[7]);
- *heightPtr = LM_to_uint(header[8],header[9]);
+ *widthPtr = LM_to_uint(header[6], header[7]);
+ *heightPtr = LM_to_uint(header[8], header[9]);
return 1;
}
/*
*----------------------------------------------------------------------
*
- * StringReadGif -- --
+ * StringReadGIF --
*
- * This procedure is called by the photo image type to read
- * GIF format data from an object, optionally base64 encoded,
- * and give it to the photo image.
+ * This procedure is called by the photo image type to read GIF format
+ * data from an object, optionally base64 encoded, and give it to the
+ * photo image.
*
* Results:
- * A standard TCL completion code. If TCL_ERROR is returned
- * then an error message is left in the interp's result.
+ * A standard TCL completion code. If TCL_ERROR is returned then an
+ * error message is left in the interp's result.
*
* Side effects:
- * new data is added to the image given by imageHandle. This
- * procedure calls FileReadGif by redefining the operation of
- * fprintf temporarily.
+ * New data is added to the image given by imageHandle. This procedure
+ * calls FileReadGIF by redefining the operation of fprintf temporarily.
*
*----------------------------------------------------------------------
*/
@@ -600,49 +624,44 @@ StringReadGIF(interp, dataObj, format, imageHandle,
Tcl_Obj *dataObj; /* object containing the image */
Tcl_Obj *format; /* format object, or NULL */
Tk_PhotoHandle imageHandle; /* the image to write this data into */
- int destX, destY; /* The rectangular region of the */
- int width, height; /* image to copy */
+ int destX, destY; /* The rectangular region of the */
+ int width, height; /* image to copy */
int srcX, srcY;
{
- int result;
MFile handle;
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_Channel dataSrc;
- char *data;
+ int length;
+ char *data = (char *) Tcl_GetByteArrayFromObj(dataObj, &length);
- /*
- * Check whether the data is Base64 encoded
- */
- data = (char *) Tcl_GetByteArrayFromObj(dataObj, NULL);
- if ((strncmp(GIF87a, data, 6) != 0) && (strncmp(GIF89a, data, 6) != 0)) {
- mInit((unsigned char *)data, &handle);
- tsdPtr->fromData = 1;
- dataSrc = (Tcl_Channel) &handle;
+ mInit((unsigned char *)data, &handle, 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).
+ */
+
+ return FileReadGIF(interp, (Tcl_Channel) &handle, INLINE_DATA_BASE64,
+ format, imageHandle, destX, destY, width, height, srcX, srcY);
} else {
- tsdPtr->fromData = 2;
- mInit((unsigned char *)data, &handle);
- dataSrc = (Tcl_Channel) &handle;
+ return FileReadGIF(interp, (Tcl_Channel) &handle, INLINE_DATA_BINARY,
+ format, imageHandle, destX, destY, width, height, srcX, srcY);
}
- result = FileReadGIF(interp, dataSrc, "inline data",
- format, imageHandle, destX, destY, width, height, srcX, srcY);
- tsdPtr->fromData = 0;
- return result;
}
-
+
/*
*----------------------------------------------------------------------
*
* ReadGIFHeader --
*
- * This procedure reads the GIF header from the beginning of a
- * GIF file and returns the dimensions of the image.
+ * This procedure reads the GIF header from the beginning of a GIF file
+ * and returns the dimensions of the image.
*
* Results:
- * The return value is 1 if file "f" appears to start with
- * a valid GIF header, 0 otherwise. If the header is valid,
- * then *widthPtr and *heightPtr are modified to hold the
- * dimensions of the image.
+ * The return value is 1 if file "f" appears to start with a valid GIF
+ * header, 0 otherwise. If the header is valid, then *widthPtr and
+ * *heightPtr are modified to hold the dimensions of the image.
*
* Side effects:
* The access position in f advances.
@@ -651,28 +670,29 @@ StringReadGIF(interp, dataObj, format, imageHandle,
*/
static int
-ReadGIFHeader(chan, widthPtr, heightPtr)
+ReadGIFHeader(gifConfPtr, chan, widthPtr, heightPtr)
+ GIFImageConfig *gifConfPtr;
Tcl_Channel chan; /* Image file to read the header from */
- int *widthPtr, *heightPtr; /* The dimensions of the image are
- * returned here. */
+ int *widthPtr, *heightPtr; /* The dimensions of the image are returned
+ * here. */
{
unsigned char buf[7];
- if ((Fread(buf, 1, 6, chan) != 6)
+ if ((Fread(gifConfPtr, buf, 1, 6, chan) != 6)
|| ((strncmp(GIF87a, (char *) buf, 6) != 0)
&& (strncmp(GIF89a, (char *) buf, 6) != 0))) {
return 0;
}
- if (Fread(buf, 1, 4, chan) != 4) {
+ if (Fread(gifConfPtr, buf, 1, 4, chan) != 4) {
return 0;
}
- *widthPtr = LM_to_uint(buf[0],buf[1]);
- *heightPtr = LM_to_uint(buf[2],buf[3]);
+ *widthPtr = LM_to_uint(buf[0], buf[1]);
+ *heightPtr = LM_to_uint(buf[2], buf[3]);
return 1;
}
-
+
/*
*-----------------------------------------------------------------
* The code below is copied from the giftoppm program and modified
@@ -681,7 +701,8 @@ ReadGIFHeader(chan, widthPtr, heightPtr)
*/
static int
-ReadColorMap(chan, number, buffer)
+ReadColorMap(gifConfPtr, chan, number, buffer)
+ GIFImageConfig *gifConfPtr;
Tcl_Channel chan;
int number;
unsigned char buffer[MAXCOLORMAPSIZE][4];
@@ -690,29 +711,28 @@ ReadColorMap(chan, number, buffer)
unsigned char rgb[3];
for (i = 0; i < number; ++i) {
- if (! ReadOK(chan, rgb, sizeof(rgb))) {
+ if (Fread(gifConfPtr, rgb, sizeof(rgb), 1, chan) <= 0) {
return 0;
}
if (buffer) {
- buffer[i][CM_RED] = rgb[0] ;
- buffer[i][CM_GREEN] = rgb[1] ;
- buffer[i][CM_BLUE] = rgb[2] ;
- buffer[i][CM_ALPHA] = 255 ;
+ buffer[i][CM_RED] = rgb[0];
+ buffer[i][CM_GREEN] = rgb[1];
+ buffer[i][CM_BLUE] = rgb[2];
+ buffer[i][CM_ALPHA] = 255;
}
}
return 1;
}
-
-
-
+
static int
-DoExtension(chan, label, transparent)
+DoExtension(gifConfPtr, chan, label, buf, transparent)
+ GIFImageConfig *gifConfPtr;
Tcl_Channel chan;
int label;
+ unsigned char *buf;
int *transparent;
{
- static unsigned char buf[256];
int count;
switch (label) {
@@ -724,12 +744,12 @@ DoExtension(chan, label, transparent)
case 0xfe: /* Comment Extension */
do {
- count = GetDataBlock(chan, (unsigned char*) buf);
+ count = GetDataBlock(gifConfPtr, chan, (unsigned char*) buf);
} while (count > 0);
return count;
case 0xf9: /* Graphic Control Extension */
- count = GetDataBlock(chan, (unsigned char*) buf);
+ count = GetDataBlock(gifConfPtr, chan, (unsigned char*) buf);
if (count < 0) {
return 1;
}
@@ -738,53 +758,52 @@ DoExtension(chan, label, transparent)
}
do {
- count = GetDataBlock(chan, (unsigned char*) buf);
+ count = GetDataBlock(gifConfPtr, chan, (unsigned char*) buf);
} while (count > 0);
return count;
}
do {
- count = GetDataBlock(chan, (unsigned char*) buf);
+ count = GetDataBlock(gifConfPtr, chan, (unsigned char*) buf);
} while (count > 0);
return count;
}
-
+
static int
-GetDataBlock(chan, buf)
+GetDataBlock(gifConfPtr, chan, buf)
+ GIFImageConfig *gifConfPtr;
Tcl_Channel chan;
unsigned char *buf;
{
unsigned char count;
- if (! ReadOK(chan, &count,1)) {
+ if (Fread(gifConfPtr, &count, 1, 1, chan) <= 0) {
return -1;
}
- if ((count != 0) && (! ReadOK(chan, buf, count))) {
+ if ((count != 0) && (Fread(gifConfPtr, buf, count, 1, chan) <= 0)) {
return -1;
}
return count;
}
-
-
/*
*----------------------------------------------------------------------
*
* ReadImage --
*
- * Process a GIF image from a given source, with a given height,
- * width, transparency, etc.
+ * Process a GIF image from a given source, with a given height, width,
+ * transparency, etc.
*
* This code is based on the code found in the ImageMagick GIF decoder,
* which is (c) 2000 ImageMagick Studio.
*
* Some thoughts on our implementation:
- * It sure would be nice if ReadImage didn't take 11 parameters! I think
+ * It sure would be nice if ReadImage didn't take 11 parameters! I think
* that if we were smarter, we could avoid doing that.
*
- * Possible further optimizations: we could pull the GetCode function
+ * Possible further optimizations: we could pull the GetCode function
* directly into ReadImage, which would improve our speed.
*
* Results:
@@ -797,8 +816,9 @@ GetDataBlock(chan, buf)
*/
static int
-ReadImage(interp, imagePtr, chan, len, rows, cmap,
+ReadImage(gifConfPtr, interp, imagePtr, chan, len, rows, cmap,
width, height, srcX, srcY, interlace, transparent)
+ GIFImageConfig *gifConfPtr;
Tcl_Interp *interp;
char *imagePtr;
Tcl_Channel chan;
@@ -816,16 +836,16 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
CONST static int interlaceStep[] = { 8, 8, 4, 2 };
CONST static 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];
+ unsigned char append[(1 << MAX_LWZ_BITS)];
+ unsigned char stack[(1 << MAX_LWZ_BITS)*2];
register unsigned char *top;
int codeSize, clearCode, inCode, endCode, oldCode, maxCode;
int code, firstCode;
/*
- * Initialize the decoder
+ * Initialize the decoder
*/
- if (! ReadOK(chan, &initialCodeSize, 1)) {
+ if (Fread(gifConfPtr, &initialCodeSize, 1, 1, chan) <= 0) {
Tcl_AppendResult(interp, "error reading GIF image: ",
Tcl_PosixError(interp), (char *) NULL);
return TCL_ERROR;
@@ -862,7 +882,7 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
}
top = stack;
- GetCode(chan, 0, 1);
+ GetCode(chan, 0, 1, gifConfPtr);
/*
* Read until we finish the image
@@ -874,17 +894,17 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
/*
* Bummer -- our stack is empty. Now we have to work!
*/
- code = GetCode(chan, codeSize, 0);
+ code = GetCode(chan, codeSize, 0, gifConfPtr);
if (code < 0) {
return TCL_OK;
}
if (code > maxCode || code == endCode) {
/*
- * If we're doing things right, we should never
- * receive a code that is greater than our current
- * maximum code. If we do, bail, because our decoder
- * does not yet have that code set up.
+ * If we're doing things right, we should never receive a
+ * code that is greater than our current maximum code. If
+ * we do, bail, because our decoder does not yet have that
+ * code set up.
*
* If the code is the magic endCode value, quit.
*/
@@ -903,12 +923,12 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
if (oldCode == -1) {
/*
- * Last pass reset the decoder, so the first code we
- * see must be a singleton. Seed the stack with it,
- * and set up the old/first code pointers for
- * insertion into the string table. We can't just
- * roll this into the clearCode test above, because
- * at that point we have not yet read the next code.
+ * Last pass reset the decoder, so the first code we see
+ * must be a singleton. Seed the stack with it, and set up
+ * the old/first code pointers for insertion into the
+ * string table. We can't just roll this into the
+ * clearCode test above, because at that point we have not
+ * yet read the next code.
*/
*top++ = append[code];
oldCode = code;
@@ -921,8 +941,8 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
if (code == maxCode) {
/*
* maxCode is always one bigger than our highest assigned
- * code. If the code we see is equal to maxCode, then
- * we are about to add a new string to the table. ???
+ * code. If the code we see is equal to maxCode, then we
+ * are about to add a new string to the table. ???
*/
*top++ = firstCode;
code = oldCode;
@@ -930,8 +950,8 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
while (code > clearCode) {
/*
- * Populate the stack by tracing the string in the
- * string table from its tail to its head
+ * Populate the stack by tracing the string in the string
+ * table from its tail to its head
*/
*top++ = append[code];
code = prefix[code];
@@ -959,11 +979,12 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
maxCode++;
/*
- * maxCode tells us the maximum code value we can accept.
- * If we see that we need more bits to represent it than
- * we are requesting from the unpacker, we need to increase
- * the number we ask for.
+ * maxCode tells us the maximum code value we can accept. If
+ * we see that we need more bits to represent it than we are
+ * requesting from the unpacker, we need to increase the
+ * number we ask for.
*/
+
if ((maxCode >= (1 << codeSize))
&& (maxCode < (1<<MAX_LWZ_BITS))) {
codeSize++;
@@ -974,6 +995,7 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
/*
* Pop the next color index off the stack.
*/
+
v = *(--top);
if (v < 0) {
return TCL_OK;
@@ -981,9 +1003,10 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
/*
* If pixelPtr is null, we're skipping this image (presumably
- * there are more in the file and we will be called to read
- * one of them later)
+ * there are more in the file and we will be called to read one of
+ * them later)
*/
+
*pixelPtr++ = cmap[v][CM_RED];
*pixelPtr++ = cmap[v][CM_GREEN];
*pixelPtr++ = cmap[v][CM_BLUE];
@@ -1013,7 +1036,6 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
}
return TCL_OK;
}
-
/*
*----------------------------------------------------------------------
@@ -1021,19 +1043,18 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
* GetCode --
*
* Extract the next compression code from the file. In GIF's, the
- * compression codes are between 3 and 12 bits long and are then
- * packed into 8 bit bytes, left to right, for example:
+ * compression codes are between 3 and 12 bits long and are then packed
+ * into 8 bit bytes, left to right, for example:
* bbbaaaaa
* dcccccbb
* eeeedddd
* ...
- * We use a byte buffer read from the file and a sliding window
- * to unpack the bytes. Thanks to ImageMagick for the sliding window
- * idea.
+ * We use a byte buffer read from the file and a sliding window to unpack
+ * the bytes. Thanks to ImageMagick for the sliding window idea.
* args: chan the channel to read from
* code_size size of the code to extract
- * flag boolean indicating whether the extractor
- * should be reset or not
+ * flag boolean indicating whether the extractor should be
+ * reset or not
*
* Results:
* code the next compression code
@@ -1045,69 +1066,65 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap,
*/
static int
-GetCode(chan, code_size, flag)
+GetCode(chan, code_size, flag, gifConfPtr)
Tcl_Channel chan;
int code_size;
int flag;
+ GIFImageConfig *gifConfPtr;
{
- static unsigned char buf[280];
- static int bytes = 0, done;
- static unsigned char *c;
-
- static unsigned int window;
- static int bitsInWindow = 0;
int ret;
if (flag) {
/*
* Initialize the decoder.
*/
- bitsInWindow = 0;
- bytes = 0;
- window = 0;
- done = 0;
- c = NULL;
+ gifConfPtr->reader.bitsInWindow = 0;
+ gifConfPtr->reader.bytes = 0;
+ gifConfPtr->reader.window = 0;
+ gifConfPtr->reader.done = 0;
+ gifConfPtr->reader.c = NULL;
return 0;
}
- while (bitsInWindow < code_size) {
+ while (gifConfPtr->reader.bitsInWindow < code_size) {
/*
* Not enough bits in our window to cover the request.
*/
- if (done) {
+ if (gifConfPtr->reader.done) {
return -1;
}
- if (bytes == 0) {
+ if (gifConfPtr->reader.bytes == 0) {
/*
* Not enough bytes in our buffer to add to the window.
*/
- bytes = GetDataBlock(chan, buf);
- c = buf;
- if (bytes <= 0) {
- done = 1;
+ gifConfPtr->reader.bytes =
+ GetDataBlock(gifConfPtr, chan, gifConfPtr->workingBuffer);
+ gifConfPtr->reader.c = gifConfPtr->reader.workingBuffer;
+ if (gifConfPtr->reader.bytes <= 0) {
+ gifConfPtr->reader.done = 1;
break;
}
}
/*
* Tack another byte onto the window, see if that's enough.
*/
- window += (*c) << bitsInWindow;
- c++;
- bitsInWindow += 8;
- bytes--;
+ gifConfPtr->reader.window +=
+ (*gifConfPtr->reader.c) << gifConfPtr->reader.bitsInWindow;
+ gifConfPtr->reader.c++;
+ gifConfPtr->reader.bitsInWindow += 8;
+ gifConfPtr->reader.bytes--;
}
-
/*
* The next code will always be the last code_size bits of the window.
*/
- ret = window & ((1 << code_size) - 1);
+ ret = gifConfPtr->reader.window & ((1 << code_size) - 1);
/*
* Shift data in the window to put the next code at the end.
*/
- window >>= code_size;
- bitsInWindow -= code_size;
+ gifConfPtr->reader.window >>= code_size;
+ gifConfPtr->reader.bitsInWindow -= code_size;
return ret;
}
@@ -1116,25 +1133,27 @@ GetCode(chan, code_size, flag)
*
* Minit -- --
*
- * This procedure initializes a base64 decoder handle
+ * This procedure initializes a base64 decoder handle
*
* Results:
- * none
+ * None
*
* Side effects:
- * the base64 handle is initialized
+ * The base64 handle is initialized
*
*----------------------------------------------------------------------
*/
static void
-mInit(string, handle)
+mInit(string, handle, length)
unsigned char *string; /* string containing initial mmencoded data */
MFile *handle; /* mmdecode "file" handle */
+ int length; /* Number of bytes in string */
{
handle->data = string;
handle->state = 0;
handle->c = 0;
+ handle->length = length;
}
/*
@@ -1142,9 +1161,9 @@ mInit(string, handle)
*
* Mread --
*
- * This procedure is invoked by the GIF file reader as a
- * temporary replacement for "fread", to get GIF data out
- * of a string (using Mgetc).
+ * This procedure is invoked by the GIF file reader as a temporary
+ * replacement for "fread", to get GIF data out of a string (using
+ * Mgetc).
*
* Results:
* The return value is the number of characters "read"
@@ -1165,14 +1184,14 @@ Mread(dst, chunkSize, numChunks, handle)
register int i, c;
int count = chunkSize * numChunks;
- for(i=0; i<count && (c=Mgetc(handle)) != GIF_DONE; i++) {
- *dst++ = c;
+ for (i=0; i<count && (c=Mgetc(handle)) != GIF_DONE; i++) {
+ *dst++ = c;
}
return i;
}
/*
- * get the next decoded character from an mmencode handle
+ * Get the next decoded character from an mmencode handle.
* This causes at least 1 character to be "read" from the encoded string
*/
@@ -1181,31 +1200,34 @@ Mread(dst, chunkSize, numChunks, handle)
*
* Mgetc --
*
- * This procedure decodes and returns the next byte from a base64
- * encoded string.
+ * This procedure decodes and returns the next byte from a base64 encoded
+ * string.
*
* Results:
- * The next byte (or GIF_DONE) is returned.
+ * The next byte (or GIF_DONE) is returned.
*
* Side effects:
- * The base64 handle will change state.
+ * The base64 handle will change state.
*
*----------------------------------------------------------------------
*/
static int
Mgetc(handle)
- MFile *handle; /* Handle containing decoder data and state */
+ MFile *handle; /* Handle containing decoder data and state */
{
int c;
- int result = 0; /* Initialization needed only to prevent
- * gcc compiler warning. */
+ int result = 0; /* Initialization needed only to prevent gcc
+ * compiler warning. */
if (handle->state == GIF_DONE) {
return GIF_DONE;
}
do {
+ if (handle->length-- <= 0) {
+ return GIF_DONE;
+ }
c = char64(*handle->data);
handle->data++;
} while (c == GIF_SPACE);
@@ -1242,20 +1264,21 @@ Mgetc(handle)
* char64 --
*
* This procedure converts a base64 ascii character into its binary
- * equivalent. This code is a slightly modified version of the
- * char64 proc in N. Borenstein's metamail decoder.
+ * equivalent. This code is a slightly modified version of the char64
+ * proc in N. Borenstein's metamail decoder.
*
* Results:
* The binary value, or an error code.
*
* Side effects:
* None.
+ *
*----------------------------------------------------------------------
*/
static int
char64(c)
-int c;
+ int c;
{
switch(c) {
case 'A': return 0; case 'B': return 1; case 'C': return 2;
@@ -1297,37 +1320,42 @@ int c;
*
* Fread --
*
- * This procedure calls either fread or Mread to read data
- * from a file or a base64 encoded string.
+ * This procedure calls either fread or Mread to read data from a file or
+ * a base64 encoded string.
*
- * Results: - same as fread
+ * Results: - same as POSIX fread() or Tcl Tcl_Read()
*
*----------------------------------------------------------------------
*/
static int
-Fread(dst, hunk, count, chan)
+Fread(gifConfPtr, dst, hunk, count, chan)
+ GIFImageConfig *gifConfPtr;
unsigned char *dst; /* where to put the result */
- size_t hunk,count; /* how many */
+ size_t hunk, count; /* how many */
Tcl_Channel chan;
{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
MFile *handle;
- switch (tsdPtr->fromData) {
- case 1:
+ if (gifConfPtr->fromData == INLINE_DATA_BASE64) {
return Mread(dst, hunk, count, (MFile *) chan);
- case 2:
+ }
+
+ if (gifConfPtr->fromData == INLINE_DATA_BINARY) {
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));
handle->data += hunk * count;
return (int)(hunk * count);
- default:
- return Tcl_Read(chan, (char *) dst, (int) (hunk * count));
}
-}
+ /*
+ * Otherwise we've got a real file to read.
+ */
+ return Tcl_Read(chan, (char *) dst, (int) (hunk * count));
+}
/*
* ChanWriteGIF - writes a image in GIF format.
@@ -1346,21 +1374,21 @@ Fread(dst, hunk, count, chan)
*----------------------------------------------------------------------
* FileWriteGIF-
*
- * This procedure is called by the photo image type to write
- * GIF format data from a photo image into a given file
+ * This procedure is called by the photo image type to write GIF format
+ * data from a photo image into a given file
*
* Results:
- * A standard TCL completion code. If TCL_ERROR is returned
- * then an error message is left in interp->result.
+ * A standard TCL completion code. If TCL_ERROR is returned then an
+ * error message is left in interp->result.
*
*----------------------------------------------------------------------
*/
- /*
- * Types, defines and variables needed to write and compress a GIF.
- */
+/*
+ * Types, defines and variables needed to write and compress a GIF.
+ */
-typedef int (* ifunptr) _ANSI_ARGS_((void));
+typedef int (* ifunptr) _ANSI_ARGS_((ClientData clientData));
#define LSB(a) ((unsigned char) (((short)(a)) & 0x00FF))
#define MSB(a) ((unsigned char) (((short)(a)) >> 8))
@@ -1368,32 +1396,37 @@ typedef int (* ifunptr) _ANSI_ARGS_((void));
#define GIFBITS 12
#define HSIZE 5003 /* 80% occupancy */
-static int ssize;
-static int csize;
-static int rsize;
-static unsigned char *pixelo;
-static int pixelSize;
-static int pixelPitch;
-static int greenOffset;
-static int blueOffset;
-static int alphaOffset;
-static int num;
-static unsigned char mapa[MAXCOLORMAPSIZE][3];
+typedef struct {
+ int ssize;
+ int csize;
+ int rsize;
+ unsigned char *pixelo;
+ int pixelSize;
+ int pixelPitch;
+ int greenOffset;
+ int blueOffset;
+ int alphaOffset;
+ int num;
+ unsigned char mapa[MAXCOLORMAPSIZE][3];
+} GifWriterState;
/*
- * Definition of new functions to write GIFs
+ * Definition of new functions to write GIFs
*/
-static int color _ANSI_ARGS_((int red,int green, int blue,
- unsigned char mapa[MAXCOLORMAPSIZE][3]));
-static void compress _ANSI_ARGS_((int init_bits, Tcl_Channel handle,
- ifunptr readValue));
-static int nuevo _ANSI_ARGS_((int red, int green ,int blue,
- unsigned char mapa[MAXCOLORMAPSIZE][3]));
-static void savemap _ANSI_ARGS_((Tk_PhotoImageBlock *blockPtr,
- unsigned char mapa[MAXCOLORMAPSIZE][3]));
-static int ReadValue _ANSI_ARGS_((void));
-
+static int color _ANSI_ARGS_((GifWriterState *statePtr,
+ int red, int green, int blue,
+ unsigned char mapa[MAXCOLORMAPSIZE][3]));
+static void compress _ANSI_ARGS_((int initBits, Tcl_Channel handle,
+ ifunptr readValue, ClientData clientData));
+static int nuevo _ANSI_ARGS_((GifWriterState *statePtr,
+ int red, int green, int blue,
+ unsigned char mapa[MAXCOLORMAPSIZE][3]));
+static void savemap _ANSI_ARGS_((GifWriterState *statePtr,
+ Tk_PhotoImageBlock *blockPtr,
+ unsigned char mapa[MAXCOLORMAPSIZE][3]));
+static int ReadValue _ANSI_ARGS_((ClientData clientData));
+
static int
FileWriteGIF(interp, filename, format, blockPtr)
Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
@@ -1408,20 +1441,20 @@ FileWriteGIF(interp, filename, format, blockPtr)
if (!chan) {
return TCL_ERROR;
}
- if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") != TCL_OK) {
+ if (Tcl_SetChannelOption(interp, chan, "-translation",
+ "binary") != TCL_OK) {
Tcl_Close(NULL, chan);
return TCL_ERROR;
}
result = CommonWriteGIF(interp, chan, format, blockPtr);
+
if (Tcl_Close(interp, chan) == TCL_ERROR) {
return TCL_ERROR;
}
return result;
}
-
-#define Mputc(c,handle) Tcl_Write(handle,(char *) &c,1)
-
+
static int
CommonWriteGIF(interp, handle, format, blockPtr)
Tcl_Interp *interp;
@@ -1429,146 +1462,149 @@ CommonWriteGIF(interp, handle, format, blockPtr)
Tcl_Obj *format;
Tk_PhotoImageBlock *blockPtr;
{
- int resolution;
-
- long width,height,x;
+ GifWriteState state, *statePtr = &state;
+ int resolution;
+ long width, height, x;
unsigned char c;
- unsigned int top,left;
+ unsigned int top, left;
top = 0;
left = 0;
- pixelSize = blockPtr->pixelSize;
- greenOffset = blockPtr->offset[1]-blockPtr->offset[0];
- blueOffset = blockPtr->offset[2]-blockPtr->offset[0];
- alphaOffset = blockPtr->offset[0];
- if (alphaOffset < blockPtr->offset[2]) {
- alphaOffset = blockPtr->offset[2];
+ memset(statePtr, 0, sizeof(state));
+
+ statePtr->pixelSize = blockPtr->pixelSize;
+ statePtr->greenOffset = blockPtr->offset[1]-blockPtr->offset[0];
+ statePtr->blueOffset = blockPtr->offset[2]-blockPtr->offset[0];
+ statePtr->alphaOffset = blockPtr->offset[0];
+ if (statePtr->alphaOffset < blockPtr->offset[2]) {
+ statePtr->alphaOffset = blockPtr->offset[2];
}
- if (++alphaOffset < pixelSize) {
- alphaOffset -= blockPtr->offset[0];
+ if (++statePtr->alphaOffset < statePtr->pixelSize) {
+ statePtr->alphaOffset -= blockPtr->offset[0];
} else {
- alphaOffset = 0;
+ statePtr->alphaOffset = 0;
}
- Tcl_Write(handle, (char *) (alphaOffset ? GIF89a : GIF87a), 6);
+ Tcl_Write(handle, (char *) (statePtr->alphaOffset ? GIF89a : GIF87a), 6);
for (x=0 ; x<MAXCOLORMAPSIZE ; x++) {
- mapa[x][CM_RED] = 255;
- mapa[x][CM_GREEN] = 255;
- mapa[x][CM_BLUE] = 255;
+ statePtr->mapa[x][CM_RED] = 255;
+ statePtr->mapa[x][CM_GREEN] = 255;
+ statePtr->mapa[x][CM_BLUE] = 255;
}
width = blockPtr->width;
height = blockPtr->height;
- pixelo = blockPtr->pixelPtr + blockPtr->offset[0];
- pixelPitch = blockPtr->pitch;
- savemap(blockPtr,mapa);
- if (num >= MAXCOLORMAPSIZE) {
+ statePtr->pixelo = blockPtr->pixelPtr + blockPtr->offset[0];
+ statePtr->pixelPitch = blockPtr->pitch;
+ savemap(statePtr, blockPtr, statePtr->mapa);
+ if (statePtr->num >= MAXCOLORMAPSIZE) {
Tcl_AppendResult(interp, "too many colors", (char *) NULL);
return TCL_ERROR;
}
- if (num<2) {
- num = 2;
+ if (statePtr->num<2) {
+ statePtr->num = 2;
}
c = LSB(width);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = MSB(width);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = LSB(height);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = MSB(height);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
resolution = 0;
- while (num >> resolution) {
+ while (statePtr->num >> resolution) {
resolution++;
}
c = 111 + resolution * 17;
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
- num = 1 << resolution;
+ statePtr->num = 1 << resolution;
/*
* background color
*/
c = 0;
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
/*
* zero for future expansion.
*/
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
- for (x=0 ; x<num ; x++) {
- c = mapa[x][CM_RED];
- Mputc(c,handle);
- c = mapa[x][CM_GREEN];
- Mputc(c,handle);
- c = mapa[x][CM_BLUE];
- Mputc(c,handle);
+ for (x=0 ; x<statePtr->num ; x++) {
+ c = statePtr->mapa[x][CM_RED];
+ Tcl_Write(handle, (char *) &c, 1);
+ c = statePtr->mapa[x][CM_GREEN];
+ Tcl_Write(handle, (char *) &c, 1);
+ c = statePtr->mapa[x][CM_BLUE];
+ Tcl_Write(handle, (char *) &c, 1);
}
/*
* Write out extension for transparent colour index, if necessary.
*/
- if (alphaOffset) {
+ if (statePtr->alphaOffset) {
c = GIF_EXTENSION;
- Mputc(c, handle);
+ Tcl_Write(handle, (char *) &c, 1);
Tcl_Write(handle, "\371\4\1\0\0\0", 7);
}
c = GIF_START;
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = LSB(top);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = MSB(top);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = LSB(left);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = MSB(left);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = LSB(width);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = MSB(width);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = LSB(height);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = MSB(height);
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = 0;
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = resolution;
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
- ssize = rsize = blockPtr->width;
- csize = blockPtr->height;
- compress(resolution+1, handle, ReadValue);
+ statePtr->ssize = statePtr->rsize = blockPtr->width;
+ statePtr->csize = blockPtr->height;
+ compress(resolution+1, handle, ReadValue, (ClientData) statePtr);
c = 0;
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
c = GIF_TERMINATOR;
- Mputc(c,handle);
+ Tcl_Write(handle, (char *) &c, 1);
return TCL_OK;
}
-
+
static int
-color(red, green, blue, mapa)
+color(statePtr, red, green, blue, mapa)
+ GifWriterState *statePtr;
int red;
int green;
int blue;
unsigned char mapa[MAXCOLORMAPSIZE][3];
{
int x;
- for (x=(alphaOffset != 0) ; x<=MAXCOLORMAPSIZE ; x++) {
+ for (x=(statePtr->alphaOffset != 0) ; x<=MAXCOLORMAPSIZE ; x++) {
if ((mapa[x][CM_RED] == red) && (mapa[x][CM_GREEN] == green) &&
(mapa[x][CM_BLUE] == blue)) {
return x;
@@ -1576,15 +1612,15 @@ color(red, green, blue, mapa)
}
return -1;
}
-
static int
-nuevo(red, green, blue, mapa)
- int red,green,blue;
+nuevo(statePtr, red, green, blue, mapa)
+ GifWriterState *statePtr;
+ int red, green, blue;
unsigned char mapa[MAXCOLORMAPSIZE][3];
{
- int x = (alphaOffset != 0);
- for (; x<=num ; x++) {
+ 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)) {
return 0;
@@ -1592,74 +1628,77 @@ nuevo(red, green, blue, mapa)
}
return 1;
}
-
+
static void
-savemap(blockPtr,mapa)
+savemap(statePtr, blockPtr, mapa)
+ GifWriterState *statePtr;
Tk_PhotoImageBlock *blockPtr;
unsigned char mapa[MAXCOLORMAPSIZE][3];
{
unsigned char *colores;
- int x,y;
- unsigned char red,green,blue;
+ int x, y;
+ unsigned char red, green, blue;
- if (alphaOffset) {
- num = 0;
+ if (statePtr->alphaOffset) {
+ statePtr->num = 0;
mapa[0][CM_RED] = 0xd9;
mapa[0][CM_GREEN] = 0xd9;
mapa[0][CM_BLUE] = 0xd9;
} else {
- num = -1;
+ statePtr->num = -1;
}
for(y=0 ; y<blockPtr->height ; y++) {
- colores = blockPtr->pixelPtr + blockPtr->offset[0]
- + y * blockPtr->pitch;
+ colores = blockPtr->pixelPtr + blockPtr->offset[0] + y*blockPtr->pitch;
for(x=0 ; x<blockPtr->width ; x++) {
- if (!alphaOffset || (colores[alphaOffset] != 0)) {
+ if (!statePtr->alphaOffset || colores[statePtr->alphaOffset]!=0) {
red = colores[0];
- green = colores[greenOffset];
- blue = colores[blueOffset];
- if (nuevo(red,green,blue,mapa)) {
- num++;
- if (num >= MAXCOLORMAPSIZE) {
+ green = colores[statePtr->greenOffset];
+ blue = colores[statePtr->blueOffset];
+ if (nuevo(statePtr, red, green, blue, mapa)) {
+ statePtr->num++;
+ if (statePtr->num >= MAXCOLORMAPSIZE) {
return;
}
- mapa[num][CM_RED] = red;
- mapa[num][CM_GREEN] = green;
- mapa[num][CM_BLUE] = blue;
+ mapa[statePtr->num][CM_RED] = red;
+ mapa[statePtr->num][CM_GREEN] = green;
+ mapa[statePtr->num][CM_BLUE] = blue;
}
}
- colores += pixelSize;
+ colores += statePtr->pixelSize;
}
}
return;
}
-
+
static int
-ReadValue()
+ReadValue(clientData)
+ ClientData clientData;
{
+ GifWriterState *statePtr = (GifWriterState *) clientData;
unsigned int col;
- if (csize == 0) {
+ if (statePtr->csize == 0) {
return EOF;
}
- if (alphaOffset && (pixelo[alphaOffset] == 0)) {
+ if (statePtr->alphaOffset && statePtr->pixelo[statePtr->alphaOffset]==0) {
col = 0;
} else {
- col = color(pixelo[0], pixelo[greenOffset], pixelo[blueOffset], mapa);
+ col = color(statePtr, statePtr->pixelo[0],
+ statePtr->pixelo[statePtr->greenOffset],
+ statePtr->pixelo[statePtr->blueOffset], statePtr->mapa);
}
- pixelo += pixelSize;
- if (--ssize <= 0) {
- ssize = rsize;
- csize--;
- pixelo += pixelPitch - (rsize * pixelSize);
+ statePtr->pixelo += statePtr->pixelSize;
+ if (--statePtr->ssize <= 0) {
+ statePtr->ssize = statePtr->rsize;
+ statePtr->csize--;
+ statePtr->pixelo += statePtr->pixelPitch
+ - (statePtr->rsize * statePtr->pixelSize);
}
return col;
}
-
-
/*
*-----------------------------------------------------------------------
*
@@ -1671,30 +1710,27 @@ ReadValue()
* http://www.hasc.com
* info@hasc.com
*
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation. This software is
- * provided "AS IS." The Hutchison Avenue Software Corporation
- * disclaims all warranties, either express or implied, including but
- * not limited to implied warranties of merchantability and fitness
- * for a particular purpose, with respect to this code and
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. This software is provided "AS IS." The Hutchison Avenue
+ * Software Corporation disclaims all warranties, either express or implied,
+ * including but not limited to implied warranties of merchantability and
+ * fitness for a particular purpose, with respect to this code and
* accompanying documentation.
*
- * The miGIF compression routines do not, strictly speaking, generate
- * files conforming to the GIF spec, since the image data is not
- * LZW-compressed (this is the point: in order to avoid transgression
- * of the Unisys patent on the LZW algorithm.) However, miGIF
- * generates data streams that any reasonably sane LZW decompresser
- * will decompress to what we want.
- *
- * miGIF compression uses run length encoding. It compresses
- * horizontal runs of pixels of the same color. This type of
- * compression gives good results on images with many runs, for
- * example images with lines, text and solid shapes on a solid-colored
- * background. It gives little or no compression on images with few
- * runs, for example digital or scanned photos.
+ * The miGIF compression routines do not, strictly speaking, generate files
+ * conforming to the GIF spec, since the image data is not LZW-compressed
+ * (this is the point: in order to avoid transgression of the Unisys patent on
+ * the LZW algorithm.) However, miGIF generates data streams that any
+ * reasonably sane LZW decompresser will decompress to what we want.
+ *
+ * miGIF compression uses run length encoding. It compresses horizontal runs
+ * of pixels of the same color. This type of compression gives good results on
+ * images with many runs, for example images with lines, text and solid shapes
+ * on a solid-colored background. It gives little or no compression on images
+ * with few runs, for example digital or scanned photos.
*
* der Mouse
* mouse@rodents.montreal.qc.ca
@@ -1702,35 +1738,36 @@ ReadValue()
*
* ivo@hasc.com
*
- * The Graphics Interchange Format(c) is the Copyright property of
- * CompuServe Incorporated. GIF(sm) is a Service Mark property of
- * CompuServe Incorporated.
+ * The Graphics Interchange Format(c) is the Copyright property of CompuServe
+ * Incorporated. GIF(sm) is a Service Mark property of CompuServe Incorporated.
*
*-----------------------------------------------------------------------
*/
-static int rl_pixel;
-static int rl_basecode;
-static int rl_count;
-static int rl_table_pixel;
-static int rl_table_max;
-static int just_cleared;
-static int out_bits;
-static int out_bits_init;
-static int out_count;
-static int out_bump;
-static int out_bump_init;
-static int out_clear;
-static int out_clear_init;
-static int max_ocodes;
-static int code_clear;
-static int code_eof;
-static unsigned int obuf;
-static int obits;
-static Tcl_Channel ofile;
-static unsigned char oblock[256];
-static int oblen;
-
+typedef struct {
+ int runlengthPixel;
+ int runlengthBaseCode;
+ int runlengthCount;
+ int runlengthTablePixel;
+ int runlengthTableMax;
+ int justCleared;
+ int outputBits;
+ int outputBitsInit;
+ int outputCount;
+ int outputBump;
+ int outputBumpInit;
+ int outputClear;
+ int outputClearInit;
+ int maxOcodes;
+ int codeClear;
+ int codeEOF;
+ unsigned int obuf;
+ int obits;
+ Tcl_Channel ofile;
+ unsigned char oblock[256];
+ int oblen;
+} miGIFState_t;
+
/*
* Used only when debugging GIF compression code
*/
@@ -1738,20 +1775,25 @@ static int oblen;
#ifdef MIGIF_DEBUGGING_ENVARS
-static int verbose_set = 0;
+/*
+ * This debugging code is _absolutely_ not thread-safe. It's also not normally
+ * enabled either.
+ */
+
+static int verboseSet = 0;
static int verbose;
-#define MIGIF_VERBOSE (verbose_set?verbose:set_verbose())
-#define DEBUGMSG(printf_args) if (MIGIF_VERBOSE) { printf printf_args; }
+#define MIGIF_VERBOSE (verboseSet?verbose:setVerbose())
+#define DEBUGMSG(printfArgs) if (MIGIF_VERBOSE) { printf printfArgs; }
static int
-set_verbose(void)
+setVerbose(void)
{
verbose = !!getenv("MIGIF_VERBOSE");
- verbose_set = 1;
+ verboseSet = 1;
return verbose;
}
-static CONST char *
+static const char *
binformat(v, nbits)
unsigned int v;
int nbits;
@@ -1776,109 +1818,116 @@ binformat(v, nbits)
*bp = '\0';
return &bufs[bhand][0];
}
-
-#else
-
-#define MIGIF_VERBOSE 0
-#define DEBUGMSG(printf_args) /* do nothing */
-
+#else /* !MIGIF_DEBUGGING_ENVARS */
+#define DEBUGMSG(printfArgs) /* do nothing */
#endif
-
+
static void
-write_block()
+writeBlock(statePtr)
+ miGIFState_t *statePtr;
{
int i;
unsigned char c;
+#ifdef MIGIF_DEBUGGING_ENVARS
if (MIGIF_VERBOSE) {
- printf("write_block %d:", oblen);
- for (i=0 ; i<oblen ; i++) {
- printf(" %02x", oblock[i]);
+ printf("writeBlock %d:", statePtr->oblen);
+ for (i=0 ; i<statePtr->oblen ; i++) {
+ printf(" %02x", statePtr->oblock[i]);
}
printf("\n");
}
- c = oblen;
- Tcl_Write(ofile, (char *) &c, 1);
- Tcl_Write(ofile, (char *) &oblock[0], oblen);
- oblen = 0;
+#endif
+ c = statePtr->oblen;
+ Tcl_Write(statePtr->ofile, (char *) &c, 1);
+ Tcl_Write(statePtr->ofile, (char *) &statePtr->oblock[0], statePtr->oblen);
+ statePtr->oblen = 0;
}
-
+
static void
-block_out(c)
+blockOut(statePtr, c)
+ miGIFState_t *statePtr;
unsigned char c;
{
- DEBUGMSG(("block_out %s\n", binformat(c, 8)));
- oblock[oblen++] = c;
- if (oblen >= 255) {
- write_block();
+ DEBUGMSG(("blockOut %s\n", binformat(c, 8)));
+ statePtr->oblock[statePtr->oblen++] = c;
+ if (statePtr->oblen >= 255) {
+ writeBlock(statePtr);
}
}
-
+
static void
-block_flush()
+blockFlush(statePtr)
+ miGIFState_t *statePtr;
{
- DEBUGMSG(("block_flush\n"));
- if (oblen > 0) {
- write_block();
+ DEBUGMSG(("blockFlush\n"));
+ if (statePtr->oblen > 0) {
+ writeBlock(statePtr);
}
}
-
+
static void
-output(val)
+output(statePtr, val)
+ miGIFState_t *statePtr;
int val;
{
- DEBUGMSG(("output %s [%s %d %d]\n", binformat(val, out_bits),
- binformat(obuf, obits), obits, out_bits));
- obuf |= val << obits;
- obits += out_bits;
- while (obits >= 8) {
- block_out(obuf&0xff);
- obuf >>= 8;
- obits -= 8;
- }
- DEBUGMSG(("output leaving [%s %d]\n", binformat(obuf, obits), obits));
+ DEBUGMSG(("output %s [%s %d %d]\n", binformat(val, statePtr->outputBits),
+ binformat(statePtr->obuf, statePtr->obits), statePtr->obits,
+ statePtr->outputBits));
+ statePtr->obuf |= val << statePtr->obits;
+ statePtr->obits += statePtr->outputBits;
+ while (statePtr->obits >= 8) {
+ blockOut(statePtr, statePtr->obuf&0xff);
+ statePtr->obuf >>= 8;
+ statePtr->obits -= 8;
+ }
+ DEBUGMSG(("output leaving [%s %d]\n",
+ binformat(statePtr->obuf, statePtr->obits), statePtr->obits));
}
-
+
static void
-output_flush()
+outputFlush(statePtr)
+ miGIFState_t *statePtr;
{
- DEBUGMSG(("output_flush\n"));
- if (obits > 0) {
- block_out(obuf);
+ DEBUGMSG(("outputFlush\n"));
+ if (statePtr->obits > 0) {
+ blockOut(statePtr, statePtr->obuf);
}
- block_flush();
+ blockFlush(statePtr);
}
-
+
static void
-did_clear()
+didClear(statePtr)
+ miGIFState_t *statePtr;
{
- DEBUGMSG(("did_clear\n"));
- out_bits = out_bits_init;
- out_bump = out_bump_init;
- out_clear = out_clear_init;
- out_count = 0;
- rl_table_max = 0;
- just_cleared = 1;
+ DEBUGMSG(("didClear\n"));
+ statePtr->outputBits = statePtr->outputBitsInit;
+ statePtr->outputBump = statePtr->outputBumpInit;
+ statePtr->outputClear = statePtr->outputClearInit;
+ statePtr->outputCount = 0;
+ statePtr->runlengthTableMax = 0;
+ statePtr->justCleared = 1;
}
-
+
static void
-output_plain(c)
+outputPlain(statePtr, c)
+ miGIFState_t *statePtr;
int c;
{
- DEBUGMSG(("output_plain %s\n", binformat(c, out_bits)));
- just_cleared = 0;
- output(c);
- out_count++;
- if (out_count >= out_bump) {
- out_bits++;
- out_bump += 1 << (out_bits - 1);
- }
- if (out_count >= out_clear) {
- output(code_clear);
- did_clear();
+ DEBUGMSG(("outputPlain %s\n", binformat(c, statePtr->outputBits)));
+ statePtr->justCleared = 0;
+ output(statePtr, c);
+ statePtr->outputCount++;
+ if (statePtr->outputCount >= statePtr->outputBump) {
+ statePtr->outputBits++;
+ statePtr->outputBump += 1 << (statePtr->outputBits - 1);
+ }
+ if (statePtr->outputCount >= statePtr->outputClear) {
+ output(statePtr, statePtr->codeClear);
+ didClear(statePtr);
}
}
-
+
static unsigned int
isqrt(x)
unsigned int x;
@@ -1898,9 +1947,9 @@ isqrt(x)
r = v;
}
}
-
+
static unsigned int
-compute_triangle_count(count, nrepcodes)
+computeTriangleCount(count, nrepcodes)
unsigned int count;
unsigned int nrepcodes;
{
@@ -1926,196 +1975,213 @@ compute_triangle_count(count, nrepcodes)
}
return cost;
}
-
+
static void
-max_out_clear()
+maxOutputClear(statePtr)
+ miGIFState_t *statePtr;
{
- out_clear = max_ocodes;
+ statePtr->outputClear = statePtr->maxOcodes;
}
-
+
static void
-reset_out_clear()
+resetOutputClear(statePtr)
+ miGIFState_t *statePtr;
{
- out_clear = out_clear_init;
- if (out_count >= out_clear) {
- output(code_clear);
- did_clear();
+ statePtr->outputClear = statePtr->outputClearInit;
+ if (statePtr->outputCount >= statePtr->outputClear) {
+ output(statePtr, statePtr->codeClear);
+ didClear(statePtr);
}
}
-
+
static void
-rl_flush_fromclear(count)
+runlengthFlushFromClear(statePtr, count)
+ miGIFState_t *statePtr;
int count;
{
int n;
- DEBUGMSG(("rl_flush_fromclear %d\n", count));
- max_out_clear();
- rl_table_pixel = rl_pixel;
+ DEBUGMSG(("runlengthFlushFromClear %d\n", count));
+ maxOutputClear(statePtr);
+ statePtr->runlengthTablePixel = statePtr->runlengthPixel;
n = 1;
while (count > 0) {
if (n == 1) {
- rl_table_max = 1;
- output_plain(rl_pixel);
+ statePtr->runlengthTableMax = 1;
+ outputPlain(statePtr, statePtr->runlengthPixel);
count--;
} else if (count >= n) {
- rl_table_max = n;
- output_plain(rl_basecode+n-2);
+ statePtr->runlengthTableMax = n;
+ outputPlain(statePtr, statePtr->runlengthBaseCode+n-2);
count -= n;
} else if (count == 1) {
- rl_table_max++;
- output_plain(rl_pixel);
+ statePtr->runlengthTableMax++;
+ outputPlain(statePtr, statePtr->runlengthPixel);
count = 0;
} else {
- rl_table_max++;
- output_plain(rl_basecode+count-2);
+ statePtr->runlengthTableMax++;
+ outputPlain(statePtr, statePtr->runlengthBaseCode+count-2);
count = 0;
}
- if (out_count == 0) {
+ if (statePtr->outputCount == 0) {
n = 1;
} else {
n++;
}
}
- reset_out_clear();
- DEBUGMSG(("rl_flush_fromclear leaving table_max=%d\n", rl_table_max));
+ resetOutputClear(statePtr);
+ DEBUGMSG(("runlengthFlushFromClear leaving tableMax=%d\n",
+ statePtr->runlengthTableMax));
}
-
+
static void
-rl_flush_clearorrep(count)
+runlengthFlushClearOrRep(statePtr, count)
+ miGIFState_t *statePtr;
int count;
{
int withclr;
- DEBUGMSG(("rl_flush_clearorrep %d\n", count));
- withclr = 1 + compute_triangle_count(count, max_ocodes);
+ DEBUGMSG(("runlengthFlushClearOrRep %d\n", count));
+ withclr = 1 + computeTriangleCount(count, statePtr->maxOcodes);
if (withclr < count) {
- output(code_clear);
- did_clear();
- rl_flush_fromclear(count);
+ output(statePtr, statePtr->codeClear);
+ didClear(statePtr);
+ runlengthFlushFromClear(statePtr, count);
} else {
for (; count>0 ; count--) {
- output_plain(rl_pixel);
+ outputPlain(statePtr, statePtr->runlengthPixel);
}
}
}
-
+
static void
-rl_flush_withtable(count)
+runlengthFlushWithTable(statePtr, count)
+ miGIFState_t *statePtr;
int count;
{
int repmax;
int repleft;
int leftover;
- DEBUGMSG(("rl_flush_withtable %d\n", count));
- repmax = count / rl_table_max;
- leftover = count % rl_table_max;
+ DEBUGMSG(("runlengthFlushWithTable %d\n", count));
+ repmax = count / statePtr->runlengthTableMax;
+ leftover = count % statePtr->runlengthTableMax;
repleft = (leftover ? 1 : 0);
- if (out_count+repmax+repleft > max_ocodes) {
- repmax = max_ocodes - out_count;
- leftover = count - (repmax * rl_table_max);
- repleft = 1 + compute_triangle_count(leftover, max_ocodes);
+ if (statePtr->outputCount+repmax+repleft > statePtr->maxOcodes) {
+ repmax = statePtr->maxOcodes - statePtr->outputCount;
+ leftover = count - (repmax * statePtr->runlengthTableMax);
+ repleft = 1 + computeTriangleCount(leftover, statePtr->maxOcodes);
}
- DEBUGMSG(("rl_flush_withtable repmax=%d leftover=%d repleft=%d\n",
+ DEBUGMSG(("runlengthFlushWithTable repmax=%d leftover=%d repleft=%d\n",
repmax, leftover, repleft));
- if (1+(int)compute_triangle_count(count, max_ocodes) < repmax+repleft) {
- output(code_clear);
- did_clear();
- rl_flush_fromclear(count);
+ if (1+(int)computeTriangleCount(count, statePtr->maxOcodes)
+ < repmax+repleft) {
+ output(statePtr, statePtr->codeClear);
+ didClear(statePtr);
+ runlengthFlushFromClear(statePtr, count);
return;
}
- max_out_clear();
+ maxOutputClear(statePtr);
for (; repmax>0 ; repmax--) {
- output_plain(rl_basecode + rl_table_max - 2);
+ outputPlain(statPtr,
+ statePtr->runlengthBaseCode + statePtr->runlengthTableMax - 2);
}
if (leftover) {
- if (just_cleared) {
- rl_flush_fromclear(leftover);
+ if (statePtr->justCleared) {
+ runlengthFlushFromClear(statePtr, leftover);
} else if (leftover == 1) {
- output_plain(rl_pixel);
+ outputPlain(statePtr, statePtr->runlengthPixel);
} else {
- output_plain(rl_basecode + leftover - 2);
+ outputPlain(statePtr, statePtr->runlengthBaseCode + leftover - 2);
}
}
- reset_out_clear();
+ resetOutputClear(statePtr);
}
-
+
static void
-rl_flush()
+runlengthFlush(statePtr)
+ miGIFState_t *statePtr;
{
- DEBUGMSG(("rl_flush [ %d %d\n", rl_count, rl_pixel));
- if (rl_count == 1) {
- output_plain(rl_pixel);
- rl_count = 0;
- DEBUGMSG(("rl_flush ]\n"));
+ DEBUGMSG(("runlengthFlush [ %d %d\n", statePtr->runlengthCount,
+ statePtr->runlengthPixel));
+ if (statePtr->runlengthCount == 1) {
+ outputPlain(statePtr, statePtr->runlengthPixel);
+ statePtr->runlengthCount = 0;
+ DEBUGMSG(("runlengthFlush ]\n"));
return;
}
- if (just_cleared) {
- rl_flush_fromclear(rl_count);
- } else if ((rl_table_max < 2) || (rl_table_pixel != rl_pixel)) {
- rl_flush_clearorrep(rl_count);
+ if (statePtr->justCleared) {
+ runlengthFlushFromClear(statePtr, statePtr->runlengthCount);
+ } else if ((statePtr->runlengthTableMax < 2)
+ || (statePtr->runlengthTablePixel != statePtr->runlengthPixel)) {
+ runlengthFlushClearOrRep(statePtr, statePtr->runlengthCount);
} else {
- rl_flush_withtable(rl_count);
+ runlengthFlushWithTable(statePtr, statePtr->runlengthCount);
}
- DEBUGMSG(("rl_flush ]\n"));
- rl_count = 0;
+ DEBUGMSG(("runlengthFlush ]\n"));
+ statePtr->runlengthCount = 0;
}
-
-
+
static void
-compress(init_bits, handle, readValue)
- int init_bits;
+compress(initBits, handle, readValue, clientData)
+ int initBits;
Tcl_Channel handle;
ifunptr readValue;
+ ClientData clientData;
{
int c;
-
- ofile = handle;
- obuf = 0;
- obits = 0;
- oblen = 0;
- code_clear = 1 << (init_bits - 1);
- code_eof = code_clear + 1;
- rl_basecode = code_eof + 1;
- out_bump_init = (1 << (init_bits - 1)) - 1;
+ miGIFState_t state, *statePtr = &state;
+
+ memset(statePtr, 0, sizeof(state));
+
+ statePtr->ofile = handle;
+ statePtr->obuf = 0;
+ statePtr->obits = 0;
+ statePtr->oblen = 0;
+ statePtr->codeClear = 1 << (initBits - 1);
+ statePtr->codeEOF = statePtr->codeClear + 1;
+ statePtr->runlengthBaseCode = statePtr->codeEOF + 1;
+ statePtr->outputBumpInit = (1 << (initBits - 1)) - 1;
/*
- * For images with a lot of runs, making out_clear_init larger
- * will give better compression.
+ * For images with a lot of runs, making outputClearInit larger will give
+ * better compression.
*/
- out_clear_init = (init_bits <= 3) ? 9 : (out_bump_init-1);
+ statePtr->outputClearInit =
+ (initBits <= 3) ? 9 : (statePtr->outputBumpInit-1);
#ifdef MIGIF_DEBUGGING_ENVARS
{
const char *ocienv;
ocienv = getenv("MIGIF_OUT_CLEAR_INIT");
if (ocienv) {
- out_clear_init = atoi(ocienv);
- DEBUGMSG(("[overriding out_clear_init to %d]\n", out_clear_init));
+ statePtr->outputClearInit = atoi(ocienv);
+ DEBUGMSG(("[overriding outputClearInit to %d]\n",
+ statePtr->outputClearInit));
}
}
#endif
- out_bits_init = init_bits;
- max_ocodes = (1 << GIFBITS) - ((1 << (out_bits_init - 1)) + 3);
- did_clear();
- output(code_clear);
- rl_count = 0;
+ statePtr->outputBitsInit = initBits;
+ statePtr->maxOcodes =
+ (1 << GIFBITS) - ((1 << (statePtr->outputBitsInit - 1)) + 3);
+ didClear(statePtr);
+ output(statePtr, statePtr->codeClear);
+ statePtr->runlengthCount = 0;
while (1) {
- c = readValue();
- if ((rl_count > 0) && (c != rl_pixel)) {
- rl_flush();
+ c = readValue(clientData);
+ if (statePtr->runlengthCount>0 && statePtr->runlengthPixel!=c) {
+ runlengthFlush(statePtr);
}
if (c == EOF) {
break;
}
- if (rl_pixel == c) {
- rl_count++;
+ if (statePtr->runlengthPixel == c) {
+ statePtr->runlengthCount++;
} else {
- rl_pixel = c;
- rl_count = 1;
+ statePtr->runlengthPixel = c;
+ statePtr->runlengthCount = 1;
}
}
- output(code_eof);
- output_flush();
+ output(statePtr, statePtr->codeEOF);
+ outputFlush(statePtr);
}
/*