4 * A photo image file handler for GIF files. Reads 87a and 89a GIF
5 * files. At present, there only is a file write function. GIF images
6 * may be read using the -data option of the photo image. The data may be
7 * given as a binary string in a Tcl_Obj or by representing
8 * the data as BASE64 encoded ascii. Derived from the giftoppm code
9 * found in the pbmplus package and tkImgFmtPPM.c in the tk4.0b2
12 * Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee
13 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
14 * Copyright (c) 1997 Australian National University
16 * See the file "license.terms" for information on usage and redistribution
17 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
19 * This file also contains code from the giftoppm program, which is
20 * copyrighted as follows:
22 * +--------------------------------------------------------------------+
23 * | Copyright 1990, David Koblas. |
24 * | Permission to use, copy, modify, and distribute this software |
25 * | and its documentation for any purpose and without fee is hereby |
26 * | granted, provided that the above copyright notice appear in all |
27 * | copies and that both that copyright notice and this permission |
28 * | notice appear in supporting documentation. This software is |
29 * | provided "as is" without express or implied warranty. |
30 * +-------------------------------------------------------------------+
36 * GIF's are represented as data in base64 format.
37 * base64 strings consist of 4 6-bit characters -> 3 8 bit bytes.
38 * A-Z, a-z, 0-9, + and / represent the 64 values (in order).
39 * '=' is a trailing padding char when the un-encoded data is not a
40 * multiple of 3 bytes. We'll ignore white space when encountered.
41 * Any other invalid character is treated as an EOF
44 #define GIF_SPECIAL (256)
45 #define GIF_PAD (GIF_SPECIAL+1)
46 #define GIF_SPACE (GIF_SPECIAL+2)
47 #define GIF_BAD (GIF_SPECIAL+3)
48 #define GIF_DONE (GIF_SPECIAL+4)
51 * structure to "mimic" FILE for Mread, so we can look like fread.
52 * The decoder state keeps track of which byte we are about to read,
56 typedef struct mFile {
57 unsigned char *data; /* mmencoded source string */
58 int c; /* bits left over from previous character */
59 int state; /* decoder state (0-4 or GIF_DONE) */
66 * Non-ASCII encoding support:
67 * Most data in a GIF image is binary and is treated as such. However,
68 * a few key bits are stashed in ASCII. If we try to compare those pieces
69 * to the char they represent, it will fail on any non-ASCII (eg, EBCDIC)
70 * system. To accomodate these systems, we test against the numeric value
71 * of the ASCII characters instead of the characters themselves. This is
72 * encoding independant.
75 static CONST char GIF87a[] = { /* ASCII GIF87a */
76 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x00
78 static CONST char GIF89a[] = { /* ASCII GIF89a */
79 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x00
81 # define GIF_TERMINATOR 0x3b /* ASCII ; */
82 # define GIF_EXTENSION 0x21 /* ASCII ! */
83 # define GIF_START 0x2c /* ASCII , */
86 * HACK ALERT!! HACK ALERT!! HACK ALERT!!
87 * This code is hard-wired for reading from files. In order to read
88 * from a data stream, we'll trick fread so we can reuse the same code.
89 * 0==from file; 1==from base64 encoded data; 2==from binary data
92 typedef struct ThreadSpecificData {
95 static Tcl_ThreadDataKey dataKey;
98 * The format record for the GIF file format:
101 static int FileMatchGIF _ANSI_ARGS_((Tcl_Channel chan, CONST char *fileName,
102 Tcl_Obj *format, int *widthPtr, int *heightPtr,
103 Tcl_Interp *interp));
104 static int FileReadGIF _ANSI_ARGS_((Tcl_Interp *interp,
105 Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format,
106 Tk_PhotoHandle imageHandle, int destX, int destY,
107 int width, int height, int srcX, int srcY));
108 static int StringMatchGIF _ANSI_ARGS_(( Tcl_Obj *dataObj,
109 Tcl_Obj *format, int *widthPtr, int *heightPtr,
110 Tcl_Interp *interp));
111 static int StringReadGIF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *dataObj,
112 Tcl_Obj *format, Tk_PhotoHandle imageHandle,
113 int destX, int destY, int width, int height,
114 int srcX, int srcY));
115 static int FileWriteGIF _ANSI_ARGS_((Tcl_Interp *interp,
116 CONST char *filename, Tcl_Obj *format,
117 Tk_PhotoImageBlock *blockPtr));
118 static int CommonWriteGIF _ANSI_ARGS_((Tcl_Interp *interp,
119 Tcl_Channel handle, Tcl_Obj *format,
120 Tk_PhotoImageBlock *blockPtr));
122 Tk_PhotoImageFormat tkImgFmtGIF = {
124 FileMatchGIF, /* fileMatchProc */
125 StringMatchGIF, /* stringMatchProc */
126 FileReadGIF, /* fileReadProc */
127 StringReadGIF, /* stringReadProc */
128 FileWriteGIF, /* fileWriteProc */
129 NULL, /* stringWriteProc */
132 #define INTERLACE 0x40
133 #define LOCALCOLORMAP 0x80
134 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
135 #define MAXCOLORMAPSIZE 256
140 #define MAX_LWZ_BITS 12
141 #define LM_to_uint(a,b) (((b)<<8)|(a))
142 #define ReadOK(file,buffer,len) (Fread(buffer, len, 1, file) != 0)
145 * Prototypes for local procedures defined in this file:
148 static int DoExtension _ANSI_ARGS_((Tcl_Channel chan, int label,
150 static int GetCode _ANSI_ARGS_((Tcl_Channel chan, int code_size,
152 static int GetDataBlock _ANSI_ARGS_((Tcl_Channel chan,
153 unsigned char *buf));
154 static int ReadColorMap _ANSI_ARGS_((Tcl_Channel chan, int number,
155 unsigned char buffer[MAXCOLORMAPSIZE][4]));
156 static int ReadGIFHeader _ANSI_ARGS_((Tcl_Channel chan,
157 int *widthPtr, int *heightPtr));
158 static int ReadImage _ANSI_ARGS_((Tcl_Interp *interp,
159 char *imagePtr, Tcl_Channel chan,
161 unsigned char cmap[MAXCOLORMAPSIZE][4],
162 int width, int height, int srcX, int srcY,
163 int interlace, int transparent));
166 * these are for the BASE64 image reader code only
169 static int Fread _ANSI_ARGS_((unsigned char *dst, size_t size,
170 size_t count, Tcl_Channel chan));
171 static int Mread _ANSI_ARGS_((unsigned char *dst, size_t size,
172 size_t count, MFile *handle));
173 static int Mgetc _ANSI_ARGS_((MFile *handle));
174 static int char64 _ANSI_ARGS_((int c));
175 static void mInit _ANSI_ARGS_((unsigned char *string,
180 *----------------------------------------------------------------------
184 * This procedure is invoked by the photo image type to see if
185 * a file contains image data in GIF format.
188 * The return value is 1 if the first characters in file f look
189 * like GIF data, and 0 otherwise.
192 * The access position in f may change.
194 *----------------------------------------------------------------------
198 FileMatchGIF(chan, fileName, format, widthPtr, heightPtr, interp)
199 Tcl_Channel chan; /* The image file, open for reading. */
200 CONST char *fileName; /* The name of the image file. */
201 Tcl_Obj *format; /* User-specified format object, or NULL. */
202 int *widthPtr, *heightPtr; /* The dimensions of the image are
203 * returned here if the file is a valid
205 Tcl_Interp *interp; /* not used */
207 return ReadGIFHeader(chan, widthPtr, heightPtr);
211 *----------------------------------------------------------------------
215 * This procedure is called by the photo image type to read
216 * GIF format data from a file and write it into a given
220 * A standard TCL completion code. If TCL_ERROR is returned
221 * then an error message is left in the interp's result.
224 * The access position in file f is changed, and new data is
225 * added to the image given by imageHandle.
227 *----------------------------------------------------------------------
231 FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY,
232 width, height, srcX, srcY)
233 Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
234 Tcl_Channel chan; /* The image file, open for reading. */
235 CONST char *fileName; /* The name of the image file. */
236 Tcl_Obj *format; /* User-specified format object, or NULL. */
237 Tk_PhotoHandle imageHandle; /* The photo image to write into. */
238 int destX, destY; /* Coordinates of top-left pixel in
239 * photo image to be written to. */
240 int width, height; /* Dimensions of block of photo image to
242 int srcX, srcY; /* Coordinates of top-left pixel to be used
243 * in image being read. */
245 int fileWidth, fileHeight;
246 int nBytes, index = 0, argc = 0, i;
248 Tk_PhotoImageBlock block;
249 unsigned char buf[100];
250 unsigned char *trashBuffer = NULL;
252 unsigned char colorMap[MAXCOLORMAPSIZE][4];
253 int transparent = -1;
254 static CONST char *optionStrings[] = {
258 if (format && Tcl_ListObjGetElements(interp, format,
259 &argc, &objv) != TCL_OK) {
262 for (i = 1; i < argc; i++) {
263 if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option name", 0,
264 &nBytes) != TCL_OK) {
268 Tcl_AppendResult(interp, "no value given for \"",
269 Tcl_GetStringFromObj(objv[i], NULL),
270 "\" option", (char *) NULL);
273 if (Tcl_GetIntFromObj(interp, objv[++i], &index) != TCL_OK) {
277 if (!ReadGIFHeader(chan, &fileWidth, &fileHeight)) {
278 Tcl_AppendResult(interp, "couldn't read GIF header from file \"",
279 fileName, "\"", NULL);
282 if ((fileWidth <= 0) || (fileHeight <= 0)) {
283 Tcl_AppendResult(interp, "GIF image file \"", fileName,
284 "\" has dimension(s) <= 0", (char *) NULL);
288 if (Fread(buf, 1, 3, chan) != 3) {
291 bitPixel = 2<<(buf[0]&0x07);
293 if (BitSet(buf[0], LOCALCOLORMAP)) { /* Global Colormap */
294 if (!ReadColorMap(chan, bitPixel, colorMap)) {
295 Tcl_AppendResult(interp, "error reading color map",
301 if ((srcX + width) > fileWidth) {
302 width = fileWidth - srcX;
304 if ((srcY + height) > fileHeight) {
305 height = fileHeight - srcY;
307 if ((width <= 0) || (height <= 0)
308 || (srcX >= fileWidth) || (srcY >= fileHeight)) {
312 Tk_PhotoExpand(imageHandle, destX + width, destY + height);
315 block.height = height;
317 block.pitch = block.pixelSize * block.width;
322 block.pixelPtr = NULL;
325 if (Fread(buf, 1, 1, chan) != 1) {
327 * Premature end of image. We should really notify
328 * the user, but for now just show garbage.
334 if (buf[0] == GIF_TERMINATOR) {
339 Tcl_AppendResult(interp,"no image data for this index",
344 if (buf[0] == GIF_EXTENSION) {
346 * This is a GIF extension.
349 if (Fread(buf, 1, 1, chan) != 1) {
350 Tcl_SetResult(interp,
351 "error reading extension function code in GIF image",
355 if (DoExtension(chan, buf[0], &transparent) < 0) {
356 Tcl_SetResult(interp, "error reading extension in GIF image",
363 if (buf[0] != GIF_START) {
365 * Not a valid start character; ignore it.
370 if (Fread(buf, 1, 9, chan) != 9) {
371 Tcl_SetResult(interp,
372 "couldn't read left/top/width/height in GIF image",
377 fileWidth = LM_to_uint(buf[4],buf[5]);
378 fileHeight = LM_to_uint(buf[6],buf[7]);
380 bitPixel = 1<<((buf[8]&0x07)+1);
384 * This is not the image we want to read: skip it.
386 if (BitSet(buf[8], LOCALCOLORMAP)) {
387 if (!ReadColorMap(chan, bitPixel, colorMap)) {
388 Tcl_AppendResult(interp,
389 "error reading color map", (char *) NULL);
395 * If we've not yet allocated a trash buffer, do so now.
397 if (trashBuffer == NULL) {
398 nBytes = fileWidth * fileHeight * 3;
400 (unsigned char *) ckalloc((unsigned int) nBytes);
404 * Slurp! Process the data for this image and stuff it in
407 * Yes, it might be more efficient here to *not* store the
408 * data (we're just going to throw it away later).
409 * However, I elected to implement it this way for good
410 * reasons. First, I wanted to avoid duplicating the
411 * (fairly complex) LWZ decoder in ReadImage. Fine, you
412 * say, why didn't you just modify it to allow the use of
413 * a NULL specifier for the output buffer? I tried that,
414 * but it negatively impacted the performance of what I
415 * think will be the common case: reading the first image
416 * in the file. Rather than marginally improve the speed
417 * of the less frequent case, I chose to maintain high
418 * performance for the common case.
420 if (ReadImage(interp, (char *) trashBuffer, chan, fileWidth,
421 fileHeight, colorMap, 0, 0, 0, 0, 0, -1) != TCL_OK) {
428 * If a trash buffer has been allocated, free it now.
430 if (trashBuffer != NULL) {
431 ckfree((char *)trashBuffer);
434 if (BitSet(buf[8], LOCALCOLORMAP)) {
435 if (!ReadColorMap(chan, bitPixel, colorMap)) {
436 Tcl_AppendResult(interp, "error reading color map",
442 index = LM_to_uint(buf[0],buf[1]);
445 destX -= srcX; width += srcX;
449 if (width > fileWidth) {
453 index = LM_to_uint(buf[2],buf[3]);
456 destY -= srcY; height += srcY;
459 if (height > fileHeight) {
463 if ((width <= 0) || (height <= 0)) {
469 block.height = height;
470 block.pixelSize = (transparent>=0) ? 4 : 3;
471 block.offset[3] = (transparent>=0) ? 3 : 0;
472 block.pitch = block.pixelSize * fileWidth;
473 nBytes = block.pitch * fileHeight;
474 block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
476 if (ReadImage(interp, (char *) block.pixelPtr, chan, fileWidth,
477 fileHeight, colorMap, fileWidth, fileHeight, srcX, srcY,
478 BitSet(buf[8], INTERLACE), transparent) != TCL_OK) {
484 Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height,
485 TK_PHOTO_COMPOSITE_SET);
488 if (block.pixelPtr) {
489 ckfree((char *) block.pixelPtr);
491 Tcl_AppendResult(interp, tkImgFmtGIF.name, (char *) NULL);
495 if (block.pixelPtr) {
496 ckfree((char *) block.pixelPtr);
503 *----------------------------------------------------------------------
507 * This procedure is invoked by the photo image type to see if
508 * an object contains image data in GIF format.
511 * The return value is 1 if the first characters in the data are
512 * like GIF data, and 0 otherwise.
515 * the size of the image is placed in widthPre and heightPtr.
517 *----------------------------------------------------------------------
521 StringMatchGIF(dataObj, format, widthPtr, heightPtr, interp)
522 Tcl_Obj *dataObj; /* the object containing the image data */
523 Tcl_Obj *format; /* the image format object, or NULL */
524 int *widthPtr; /* where to put the string width */
525 int *heightPtr; /* where to put the string height */
526 Tcl_Interp *interp; /* not used */
528 unsigned char *data, header[10];
532 data = Tcl_GetByteArrayFromObj(dataObj, &length);
535 * Header is a minimum of 10 bytes.
542 * Check whether the data is Base64 encoded.
545 if ((strncmp(GIF87a, (char *) data, 6) != 0) &&
546 (strncmp(GIF89a, (char *) data, 6) != 0)) {
548 * Try interpreting the data as Base64 encoded
550 mInit((unsigned char *) data, &handle);
551 got = Mread(header, 10, 1, &handle);
553 || ((strncmp(GIF87a, (char *) header, 6) != 0)
554 && (strncmp(GIF89a, (char *) header, 6) != 0))) {
558 memcpy((VOID *) header, (VOID *) data, 10);
560 *widthPtr = LM_to_uint(header[6],header[7]);
561 *heightPtr = LM_to_uint(header[8],header[9]);
566 *----------------------------------------------------------------------
568 * StringReadGif -- --
570 * This procedure is called by the photo image type to read
571 * GIF format data from an object, optionally base64 encoded,
572 * and give it to the photo image.
575 * A standard TCL completion code. If TCL_ERROR is returned
576 * then an error message is left in the interp's result.
579 * new data is added to the image given by imageHandle. This
580 * procedure calls FileReadGif by redefining the operation of
581 * fprintf temporarily.
583 *----------------------------------------------------------------------
587 StringReadGIF(interp, dataObj, format, imageHandle,
588 destX, destY, width, height, srcX, srcY)
589 Tcl_Interp *interp; /* interpreter for reporting errors in */
590 Tcl_Obj *dataObj; /* object containing the image */
591 Tcl_Obj *format; /* format object, or NULL */
592 Tk_PhotoHandle imageHandle; /* the image to write this data into */
593 int destX, destY; /* The rectangular region of the */
594 int width, height; /* image to copy */
599 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
600 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
605 * Check whether the data is Base64 encoded
607 data = (char *) Tcl_GetByteArrayFromObj(dataObj, NULL);
608 if ((strncmp(GIF87a, data, 6) != 0) && (strncmp(GIF89a, data, 6) != 0)) {
609 mInit((unsigned char *)data, &handle);
610 tsdPtr->fromData = 1;
611 dataSrc = (Tcl_Channel) &handle;
613 tsdPtr->fromData = 2;
614 mInit((unsigned char *)data, &handle);
615 dataSrc = (Tcl_Channel) &handle;
617 result = FileReadGIF(interp, dataSrc, "inline data",
618 format, imageHandle, destX, destY, width, height, srcX, srcY);
619 tsdPtr->fromData = 0;
624 *----------------------------------------------------------------------
628 * This procedure reads the GIF header from the beginning of a
629 * GIF file and returns the dimensions of the image.
632 * The return value is 1 if file "f" appears to start with
633 * a valid GIF header, 0 otherwise. If the header is valid,
634 * then *widthPtr and *heightPtr are modified to hold the
635 * dimensions of the image.
638 * The access position in f advances.
640 *----------------------------------------------------------------------
644 ReadGIFHeader(chan, widthPtr, heightPtr)
645 Tcl_Channel chan; /* Image file to read the header from */
646 int *widthPtr, *heightPtr; /* The dimensions of the image are
649 unsigned char buf[7];
651 if ((Fread(buf, 1, 6, chan) != 6)
652 || ((strncmp(GIF87a, (char *) buf, 6) != 0)
653 && (strncmp(GIF89a, (char *) buf, 6) != 0))) {
657 if (Fread(buf, 1, 4, chan) != 4) {
661 *widthPtr = LM_to_uint(buf[0],buf[1]);
662 *heightPtr = LM_to_uint(buf[2],buf[3]);
667 *-----------------------------------------------------------------
668 * The code below is copied from the giftoppm program and modified
670 *-----------------------------------------------------------------
674 ReadColorMap(chan, number, buffer)
677 unsigned char buffer[MAXCOLORMAPSIZE][4];
680 unsigned char rgb[3];
682 for (i = 0; i < number; ++i) {
683 if (! ReadOK(chan, rgb, sizeof(rgb))) {
688 buffer[i][CM_RED] = rgb[0] ;
689 buffer[i][CM_GREEN] = rgb[1] ;
690 buffer[i][CM_BLUE] = rgb[2] ;
691 buffer[i][CM_ALPHA] = 255 ;
700 DoExtension(chan, label, transparent)
705 static unsigned char buf[256];
709 case 0x01: /* Plain Text Extension */
712 case 0xff: /* Application Extension */
715 case 0xfe: /* Comment Extension */
717 count = GetDataBlock(chan, (unsigned char*) buf);
721 case 0xf9: /* Graphic Control Extension */
722 count = GetDataBlock(chan, (unsigned char*) buf);
726 if ((buf[0] & 0x1) != 0) {
727 *transparent = buf[3];
731 count = GetDataBlock(chan, (unsigned char*) buf);
737 count = GetDataBlock(chan, (unsigned char*) buf);
742 static int ZeroDataBlock = 0;
745 GetDataBlock(chan, buf)
751 if (! ReadOK(chan, &count,1)) {
755 ZeroDataBlock = count == 0;
757 if ((count != 0) && (! ReadOK(chan, buf, count))) {
767 *----------------------------------------------------------------------
771 * Process a GIF image from a given source, with a given height,
772 * width, transparency, etc.
774 * This code is based on the code found in the ImageMagick GIF decoder,
775 * which is (c) 2000 ImageMagick Studio.
777 * Some thoughts on our implementation:
778 * It sure would be nice if ReadImage didn't take 11 parameters! I think
779 * that if we were smarter, we could avoid doing that.
781 * Possible further optimizations: we could pull the GetCode function
782 * directly into ReadImage, which would improve our speed.
785 * Processes a GIF image and loads the pixel data into a memory array.
790 *----------------------------------------------------------------------
794 ReadImage(interp, imagePtr, chan, len, rows, cmap,
795 width, height, srcX, srcY, interlace, transparent)
800 unsigned char cmap[MAXCOLORMAPSIZE][4];
806 unsigned char initialCodeSize;
808 int xpos = 0, ypos = 0, pass = 0, i;
809 register char *pixelPtr;
810 CONST static int interlaceStep[] = { 8, 8, 4, 2 };
811 CONST static int interlaceStart[] = { 0, 4, 2, 1 };
812 unsigned short prefix[(1 << MAX_LWZ_BITS)];
813 unsigned char append[(1 << MAX_LWZ_BITS)];
814 unsigned char stack[(1 << MAX_LWZ_BITS)*2];
815 register unsigned char *top;
816 int codeSize, clearCode, inCode, endCode, oldCode, maxCode;
820 * Initialize the decoder
822 if (! ReadOK(chan, &initialCodeSize, 1)) {
823 Tcl_AppendResult(interp, "error reading GIF image: ",
824 Tcl_PosixError(interp), (char *) NULL);
827 if (transparent != -1) {
828 cmap[transparent][CM_RED] = 0;
829 cmap[transparent][CM_GREEN] = 0;
830 cmap[transparent][CM_BLUE] = 0;
831 cmap[transparent][CM_ALPHA] = 0;
837 * Initialize the decoder.
839 * Set values for "special" numbers:
840 * clear code reset the decoder
841 * end code stop decoding
842 * code size size of the next code to retrieve
843 * max code next available table position
845 clearCode = 1 << (int) initialCodeSize;
846 endCode = clearCode + 1;
847 codeSize = (int) initialCodeSize + 1;
848 maxCode = clearCode + 2;
852 memset((void *)prefix, 0, (1 << MAX_LWZ_BITS) * sizeof(short));
853 memset((void *)append, 0, (1 << MAX_LWZ_BITS) * sizeof(char));
854 for (i = 0; i < clearCode; i++) {
862 * Read until we finish the image
864 for (i = 0, ypos = 0; i < rows; i++) {
865 for (xpos = 0; xpos < len; ) {
869 * Bummer -- our stack is empty. Now we have to work!
871 code = GetCode(chan, codeSize, 0);
876 if (code > maxCode || code == endCode) {
878 * If we're doing things right, we should never
879 * receive a code that is greater than our current
880 * maximum code. If we do, bail, because our decoder
881 * does not yet have that code set up.
883 * If the code is the magic endCode value, quit.
888 if (code == clearCode) {
892 codeSize = initialCodeSize + 1;
893 maxCode = clearCode + 2;
900 * Last pass reset the decoder, so the first code we
901 * see must be a singleton. Seed the stack with it,
902 * and set up the old/first code pointers for
903 * insertion into the string table. We can't just
904 * roll this into the clearCode test above, because
905 * at that point we have not yet read the next code.
907 *top++ = append[code];
915 if (code == maxCode) {
917 * maxCode is always one bigger than our highest assigned
918 * code. If the code we see is equal to maxCode, then
919 * we are about to add a new string to the table. ???
925 while (code > clearCode) {
927 * Populate the stack by tracing the string in the
928 * string table from its tail to its head
930 *top++ = append[code];
933 firstCode = append[code];
936 * If there's no more room in our string table, quit.
937 * Otherwise, add a new string to the table
939 if (maxCode >= (1 << MAX_LWZ_BITS)) {
944 * Push the head of the string onto the stack.
949 * Add a new string to the string table
951 prefix[maxCode] = oldCode;
952 append[maxCode] = firstCode;
956 * maxCode tells us the maximum code value we can accept.
957 * If we see that we need more bits to represent it than
958 * we are requesting from the unpacker, we need to increase
959 * the number we ask for.
961 if ((maxCode >= (1 << codeSize))
962 && (maxCode < (1<<MAX_LWZ_BITS))) {
969 * Pop the next color index off the stack.
977 * If pixelPtr is null, we're skipping this image (presumably
978 * there are more in the file and we will be called to read
981 *pixelPtr++ = cmap[v][CM_RED];
982 *pixelPtr++ = cmap[v][CM_GREEN];
983 *pixelPtr++ = cmap[v][CM_BLUE];
984 if (transparent >= 0) {
985 *pixelPtr++ = cmap[v][CM_ALPHA];
992 * If interlacing, the next ypos is not just +1
995 ypos += interlaceStep[pass];
996 while (ypos >= height) {
1001 ypos = interlaceStart[pass];
1006 pixelPtr = imagePtr + (ypos) * len * ((transparent>=0)?4:3);
1013 *----------------------------------------------------------------------
1017 * Extract the next compression code from the file. In GIF's, the
1018 * compression codes are between 3 and 12 bits long and are then
1019 * packed into 8 bit bytes, left to right, for example:
1024 * We use a byte buffer read from the file and a sliding window
1025 * to unpack the bytes. Thanks to ImageMagick for the sliding window
1027 * args: chan the channel to read from
1028 * code_size size of the code to extract
1029 * flag boolean indicating whether the extractor
1030 * should be reset or not
1033 * code the next compression code
1036 * May consume more input from chan.
1038 *----------------------------------------------------------------------
1042 GetCode(chan, code_size, flag)
1047 static unsigned char buf[280];
1048 static int bytes = 0, done;
1049 static unsigned char *c;
1051 static unsigned int window;
1052 static int bitsInWindow = 0;
1057 * Initialize the decoder.
1067 while (bitsInWindow < code_size) {
1069 * Not enough bits in our window to cover the request.
1076 * Not enough bytes in our buffer to add to the window.
1078 bytes = GetDataBlock(chan, buf);
1086 * Tack another byte onto the window, see if that's enough.
1088 window += (*c) << bitsInWindow;
1096 * The next code will always be the last code_size bits of the window.
1098 ret = window & ((1 << code_size) - 1);
1101 * Shift data in the window to put the next code at the end.
1103 window >>= code_size;
1104 bitsInWindow -= code_size;
1109 *----------------------------------------------------------------------
1113 * This procedure initializes a base64 decoder handle
1119 * the base64 handle is initialized
1121 *----------------------------------------------------------------------
1125 mInit(string, handle)
1126 unsigned char *string; /* string containing initial mmencoded data */
1127 MFile *handle; /* mmdecode "file" handle */
1129 handle->data = string;
1135 *----------------------------------------------------------------------
1139 * This procedure is invoked by the GIF file reader as a
1140 * temporary replacement for "fread", to get GIF data out
1141 * of a string (using Mgetc).
1144 * The return value is the number of characters "read"
1147 * The base64 handle will change state.
1149 *----------------------------------------------------------------------
1153 Mread(dst, chunkSize, numChunks, handle)
1154 unsigned char *dst; /* where to put the result */
1155 size_t chunkSize; /* size of each transfer */
1156 size_t numChunks; /* number of chunks */
1157 MFile *handle; /* mmdecode "file" handle */
1160 int count = chunkSize * numChunks;
1162 for(i=0; i<count && (c=Mgetc(handle)) != GIF_DONE; i++) {
1169 * get the next decoded character from an mmencode handle
1170 * This causes at least 1 character to be "read" from the encoded string
1174 *----------------------------------------------------------------------
1178 * This procedure decodes and returns the next byte from a base64
1182 * The next byte (or GIF_DONE) is returned.
1185 * The base64 handle will change state.
1187 *----------------------------------------------------------------------
1192 MFile *handle; /* Handle containing decoder data and state */
1195 int result = 0; /* Initialization needed only to prevent
1196 * gcc compiler warning. */
1198 if (handle->state == GIF_DONE) {
1203 c = char64(*handle->data);
1205 } while (c == GIF_SPACE);
1207 if (c>GIF_SPECIAL) {
1208 handle->state = GIF_DONE;
1212 switch (handle->state++) {
1215 result = Mgetc(handle);
1218 result = handle->c | (c>>4);
1219 handle->c = (c&0xF)<<4;
1222 result = handle->c | (c>>2);
1223 handle->c = (c&0x3) << 6;
1226 result = handle->c | c;
1234 *----------------------------------------------------------------------
1238 * This procedure converts a base64 ascii character into its binary
1239 * equivalent. This code is a slightly modified version of the
1240 * char64 proc in N. Borenstein's metamail decoder.
1243 * The binary value, or an error code.
1247 *----------------------------------------------------------------------
1255 case 'A': return 0; case 'B': return 1; case 'C': return 2;
1256 case 'D': return 3; case 'E': return 4; case 'F': return 5;
1257 case 'G': return 6; case 'H': return 7; case 'I': return 8;
1258 case 'J': return 9; case 'K': return 10; case 'L': return 11;
1259 case 'M': return 12; case 'N': return 13; case 'O': return 14;
1260 case 'P': return 15; case 'Q': return 16; case 'R': return 17;
1261 case 'S': return 18; case 'T': return 19; case 'U': return 20;
1262 case 'V': return 21; case 'W': return 22; case 'X': return 23;
1263 case 'Y': return 24; case 'Z': return 25; case 'a': return 26;
1264 case 'b': return 27; case 'c': return 28; case 'd': return 29;
1265 case 'e': return 30; case 'f': return 31; case 'g': return 32;
1266 case 'h': return 33; case 'i': return 34; case 'j': return 35;
1267 case 'k': return 36; case 'l': return 37; case 'm': return 38;
1268 case 'n': return 39; case 'o': return 40; case 'p': return 41;
1269 case 'q': return 42; case 'r': return 43; case 's': return 44;
1270 case 't': return 45; case 'u': return 46; case 'v': return 47;
1271 case 'w': return 48; case 'x': return 49; case 'y': return 50;
1272 case 'z': return 51; case '0': return 52; case '1': return 53;
1273 case '2': return 54; case '3': return 55; case '4': return 56;
1274 case '5': return 57; case '6': return 58; case '7': return 59;
1275 case '8': return 60; case '9': return 61; case '+': return 62;
1276 case '/': return 63;
1278 case ' ': case '\t': case '\n': case '\r': case '\f':
1290 *----------------------------------------------------------------------
1294 * This procedure calls either fread or Mread to read data
1295 * from a file or a base64 encoded string.
1297 * Results: - same as fread
1299 *----------------------------------------------------------------------
1303 Fread(dst, hunk, count, chan)
1304 unsigned char *dst; /* where to put the result */
1305 size_t hunk,count; /* how many */
1308 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1309 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1312 switch (tsdPtr->fromData) {
1314 return Mread(dst, hunk, count, (MFile *) chan);
1316 handle = (MFile *) chan;
1317 memcpy((VOID *)dst, (VOID *) handle->data, (size_t) (hunk * count));
1318 handle->data += hunk * count;
1319 return (int)(hunk * count);
1321 return Tcl_Read(chan, (char *) dst, (int) (hunk * count));
1327 * ChanWriteGIF - writes a image in GIF format.
1328 *-------------------------------------------------------------------------
1330 * Engeneering Projects Area
1331 * Department of Mining
1332 * University of Oviedo
1333 * e-mail zz11425958@zeus.etsimo.uniovi.es
1334 * lolo@pcsig22.etsimo.uniovi.es
1335 * Date: Fri September 20 1996
1337 * Modified for transparency handling (gif89a) and miGIF compression
1338 * by Jan Nijtmans <j.nijtmans@chello.nl>
1340 *----------------------------------------------------------------------
1343 * This procedure is called by the photo image type to write
1344 * GIF format data from a photo image into a given file
1347 * A standard TCL completion code. If TCL_ERROR is returned
1348 * then an error message is left in interp->result.
1350 *----------------------------------------------------------------------
1354 * Types, defines and variables needed to write and compress a GIF.
1357 typedef int (* ifunptr) _ANSI_ARGS_((void));
1359 #define LSB(a) ((unsigned char) (((short)(a)) & 0x00FF))
1360 #define MSB(a) ((unsigned char) (((short)(a)) >> 8))
1363 #define HSIZE 5003 /* 80% occupancy */
1368 static unsigned char *pixelo;
1369 static int pixelSize;
1370 static int pixelPitch;
1371 static int greenOffset;
1372 static int blueOffset;
1373 static int alphaOffset;
1375 static unsigned char mapa[MAXCOLORMAPSIZE][3];
1378 * Definition of new functions to write GIFs
1381 static int color _ANSI_ARGS_((int red,int green, int blue,
1382 unsigned char mapa[MAXCOLORMAPSIZE][3]));
1383 static void compress _ANSI_ARGS_((int init_bits, Tcl_Channel handle,
1384 ifunptr readValue));
1385 static int nuevo _ANSI_ARGS_((int red, int green ,int blue,
1386 unsigned char mapa[MAXCOLORMAPSIZE][3]));
1387 static void savemap _ANSI_ARGS_((Tk_PhotoImageBlock *blockPtr,
1388 unsigned char mapa[MAXCOLORMAPSIZE][3]));
1389 static int ReadValue _ANSI_ARGS_((void));
1392 FileWriteGIF(interp, filename, format, blockPtr)
1393 Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
1394 CONST char *filename;
1396 Tk_PhotoImageBlock *blockPtr;
1398 Tcl_Channel chan = NULL;
1401 chan = Tcl_OpenFileChannel(interp, (char *) filename, "w", 0644);
1405 if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") != TCL_OK) {
1406 Tcl_Close(NULL, chan);
1410 result = CommonWriteGIF(interp, chan, format, blockPtr);
1411 if (Tcl_Close(interp, chan) == TCL_ERROR) {
1417 #define Mputc(c,handle) Tcl_Write(handle,(char *) &c,1)
1420 CommonWriteGIF(interp, handle, format, blockPtr)
1424 Tk_PhotoImageBlock *blockPtr;
1428 long width,height,x;
1430 unsigned int top,left;
1435 pixelSize = blockPtr->pixelSize;
1436 greenOffset = blockPtr->offset[1]-blockPtr->offset[0];
1437 blueOffset = blockPtr->offset[2]-blockPtr->offset[0];
1438 alphaOffset = blockPtr->offset[0];
1439 if (alphaOffset < blockPtr->offset[2]) {
1440 alphaOffset = blockPtr->offset[2];
1442 if (++alphaOffset < pixelSize) {
1443 alphaOffset -= blockPtr->offset[0];
1448 Tcl_Write(handle, (char *) (alphaOffset ? GIF89a : GIF87a), 6);
1450 for (x=0 ; x<MAXCOLORMAPSIZE ; x++) {
1451 mapa[x][CM_RED] = 255;
1452 mapa[x][CM_GREEN] = 255;
1453 mapa[x][CM_BLUE] = 255;
1457 width = blockPtr->width;
1458 height = blockPtr->height;
1459 pixelo = blockPtr->pixelPtr + blockPtr->offset[0];
1460 pixelPitch = blockPtr->pitch;
1461 savemap(blockPtr,mapa);
1462 if (num >= MAXCOLORMAPSIZE) {
1463 Tcl_AppendResult(interp, "too many colors", (char *) NULL);
1479 while (num >> resolution) {
1482 c = 111 + resolution * 17;
1485 num = 1 << resolution;
1495 * zero for future expansion.
1500 for (x=0 ; x<num ; x++) {
1501 c = mapa[x][CM_RED];
1503 c = mapa[x][CM_GREEN];
1505 c = mapa[x][CM_BLUE];
1510 * Write out extension for transparent colour index, if necessary.
1516 Tcl_Write(handle, "\371\4\1\0\0\0", 7);
1545 ssize = rsize = blockPtr->width;
1546 csize = blockPtr->height;
1547 compress(resolution+1, handle, ReadValue);
1558 color(red, green, blue, mapa)
1562 unsigned char mapa[MAXCOLORMAPSIZE][3];
1565 for (x=(alphaOffset != 0) ; x<=MAXCOLORMAPSIZE ; x++) {
1566 if ((mapa[x][CM_RED] == red) && (mapa[x][CM_GREEN] == green) &&
1567 (mapa[x][CM_BLUE] == blue)) {
1576 nuevo(red, green, blue, mapa)
1578 unsigned char mapa[MAXCOLORMAPSIZE][3];
1580 int x = (alphaOffset != 0);
1581 for (; x<=num ; x++) {
1582 if ((mapa[x][CM_RED] == red) && (mapa[x][CM_GREEN] == green) &&
1583 (mapa[x][CM_BLUE] == blue)) {
1591 savemap(blockPtr,mapa)
1592 Tk_PhotoImageBlock *blockPtr;
1593 unsigned char mapa[MAXCOLORMAPSIZE][3];
1595 unsigned char *colores;
1597 unsigned char red,green,blue;
1601 mapa[0][CM_RED] = 0xd9;
1602 mapa[0][CM_GREEN] = 0xd9;
1603 mapa[0][CM_BLUE] = 0xd9;
1608 for(y=0 ; y<blockPtr->height ; y++) {
1609 colores = blockPtr->pixelPtr + blockPtr->offset[0]
1610 + y * blockPtr->pitch;
1611 for(x=0 ; x<blockPtr->width ; x++) {
1612 if (!alphaOffset || (colores[alphaOffset] != 0)) {
1614 green = colores[greenOffset];
1615 blue = colores[blueOffset];
1616 if (nuevo(red,green,blue,mapa)) {
1618 if (num >= MAXCOLORMAPSIZE) {
1621 mapa[num][CM_RED] = red;
1622 mapa[num][CM_GREEN] = green;
1623 mapa[num][CM_BLUE] = blue;
1626 colores += pixelSize;
1640 if (alphaOffset && (pixelo[alphaOffset] == 0)) {
1643 col = color(pixelo[0], pixelo[greenOffset], pixelo[blueOffset], mapa);
1645 pixelo += pixelSize;
1649 pixelo += pixelPitch - (rsize * pixelSize);
1658 *-----------------------------------------------------------------------
1660 * miGIF Compression - mouse and ivo's GIF-compatible compression
1662 * -run length encoding compression routines-
1664 * Copyright (C) 1998 Hutchison Avenue Software Corporation
1665 * http://www.hasc.com
1668 * Permission to use, copy, modify, and distribute this software and
1669 * its documentation for any purpose and without fee is hereby
1670 * granted, provided that the above copyright notice appear in all
1671 * copies and that both that copyright notice and this permission
1672 * notice appear in supporting documentation. This software is
1673 * provided "AS IS." The Hutchison Avenue Software Corporation
1674 * disclaims all warranties, either express or implied, including but
1675 * not limited to implied warranties of merchantability and fitness
1676 * for a particular purpose, with respect to this code and
1677 * accompanying documentation.
1679 * The miGIF compression routines do not, strictly speaking, generate
1680 * files conforming to the GIF spec, since the image data is not
1681 * LZW-compressed (this is the point: in order to avoid transgression
1682 * of the Unisys patent on the LZW algorithm.) However, miGIF
1683 * generates data streams that any reasonably sane LZW decompresser
1684 * will decompress to what we want.
1686 * miGIF compression uses run length encoding. It compresses
1687 * horizontal runs of pixels of the same color. This type of
1688 * compression gives good results on images with many runs, for
1689 * example images with lines, text and solid shapes on a solid-colored
1690 * background. It gives little or no compression on images with few
1691 * runs, for example digital or scanned photos.
1694 * mouse@rodents.montreal.qc.ca
1695 * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
1699 * The Graphics Interchange Format(c) is the Copyright property of
1700 * CompuServe Incorporated. GIF(sm) is a Service Mark property of
1701 * CompuServe Incorporated.
1703 *-----------------------------------------------------------------------
1706 static int rl_pixel;
1707 static int rl_basecode;
1708 static int rl_count;
1709 static int rl_table_pixel;
1710 static int rl_table_max;
1711 static int just_cleared;
1712 static int out_bits;
1713 static int out_bits_init;
1714 static int out_count;
1715 static int out_bump;
1716 static int out_bump_init;
1717 static int out_clear;
1718 static int out_clear_init;
1719 static int max_ocodes;
1720 static int code_clear;
1721 static int code_eof;
1722 static unsigned int obuf;
1724 static Tcl_Channel ofile;
1725 static unsigned char oblock[256];
1729 * Used only when debugging GIF compression code
1731 /* #define MIGIF_DEBUGGING_ENVARS */
1733 #ifdef MIGIF_DEBUGGING_ENVARS
1735 static int verbose_set = 0;
1737 #define MIGIF_VERBOSE (verbose_set?verbose:set_verbose())
1738 #define DEBUGMSG(printf_args) if (MIGIF_VERBOSE) { printf printf_args; }
1743 verbose = !!getenv("MIGIF_VERBOSE");
1753 static char bufs[8][64];
1754 static int bhand = 0;
1761 bhand = (sizeof(bufs) / sizeof(bufs[0])) - 1;
1763 bp = &bufs[bhand][0];
1764 for (bno=nbits-1,bit=((unsigned int)1)<<bno ; bno>=0 ; bno--,bit>>=1) {
1765 *bp++ = (v & bit) ? '1' : '0';
1766 if (((bno&3) == 0) && (bno != 0)) {
1771 return &bufs[bhand][0];
1776 #define MIGIF_VERBOSE 0
1777 #define DEBUGMSG(printf_args) /* do nothing */
1787 if (MIGIF_VERBOSE) {
1788 printf("write_block %d:", oblen);
1789 for (i=0 ; i<oblen ; i++) {
1790 printf(" %02x", oblock[i]);
1795 Tcl_Write(ofile, (char *) &c, 1);
1796 Tcl_Write(ofile, (char *) &oblock[0], oblen);
1804 DEBUGMSG(("block_out %s\n", binformat(c, 8)));
1805 oblock[oblen++] = c;
1814 DEBUGMSG(("block_flush\n"));
1824 DEBUGMSG(("output %s [%s %d %d]\n", binformat(val, out_bits),
1825 binformat(obuf, obits), obits, out_bits));
1826 obuf |= val << obits;
1828 while (obits >= 8) {
1829 block_out(obuf&0xff);
1833 DEBUGMSG(("output leaving [%s %d]\n", binformat(obuf, obits), obits));
1839 DEBUGMSG(("output_flush\n"));
1849 DEBUGMSG(("did_clear\n"));
1850 out_bits = out_bits_init;
1851 out_bump = out_bump_init;
1852 out_clear = out_clear_init;
1862 DEBUGMSG(("output_plain %s\n", binformat(c, out_bits)));
1866 if (out_count >= out_bump) {
1868 out_bump += 1 << (out_bits - 1);
1870 if (out_count >= out_clear) {
1886 for (v=x,r=1 ; v ; v>>=2,r<<=1);
1888 v = ((x / r) + r) / 2;
1889 if (v==r || v==r+1) {
1897 compute_triangle_count(count, nrepcodes)
1899 unsigned int nrepcodes;
1901 unsigned int perrep;
1905 perrep = (nrepcodes * (nrepcodes+1)) / 2;
1906 while (count >= perrep) {
1913 while (n*(n+1) >= 2*count) {
1916 while (n*(n+1) < 2*count) {
1927 out_clear = max_ocodes;
1933 out_clear = out_clear_init;
1934 if (out_count >= out_clear) {
1941 rl_flush_fromclear(count)
1946 DEBUGMSG(("rl_flush_fromclear %d\n", count));
1948 rl_table_pixel = rl_pixel;
1953 output_plain(rl_pixel);
1955 } else if (count >= n) {
1957 output_plain(rl_basecode+n-2);
1959 } else if (count == 1) {
1961 output_plain(rl_pixel);
1965 output_plain(rl_basecode+count-2);
1968 if (out_count == 0) {
1975 DEBUGMSG(("rl_flush_fromclear leaving table_max=%d\n", rl_table_max));
1979 rl_flush_clearorrep(count)
1984 DEBUGMSG(("rl_flush_clearorrep %d\n", count));
1985 withclr = 1 + compute_triangle_count(count, max_ocodes);
1986 if (withclr < count) {
1989 rl_flush_fromclear(count);
1991 for (; count>0 ; count--) {
1992 output_plain(rl_pixel);
1998 rl_flush_withtable(count)
2005 DEBUGMSG(("rl_flush_withtable %d\n", count));
2006 repmax = count / rl_table_max;
2007 leftover = count % rl_table_max;
2008 repleft = (leftover ? 1 : 0);
2009 if (out_count+repmax+repleft > max_ocodes) {
2010 repmax = max_ocodes - out_count;
2011 leftover = count - (repmax * rl_table_max);
2012 repleft = 1 + compute_triangle_count(leftover, max_ocodes);
2014 DEBUGMSG(("rl_flush_withtable repmax=%d leftover=%d repleft=%d\n",
2015 repmax, leftover, repleft));
2016 if (1+(int)compute_triangle_count(count, max_ocodes) < repmax+repleft) {
2019 rl_flush_fromclear(count);
2023 for (; repmax>0 ; repmax--) {
2024 output_plain(rl_basecode + rl_table_max - 2);
2028 rl_flush_fromclear(leftover);
2029 } else if (leftover == 1) {
2030 output_plain(rl_pixel);
2032 output_plain(rl_basecode + leftover - 2);
2041 DEBUGMSG(("rl_flush [ %d %d\n", rl_count, rl_pixel));
2042 if (rl_count == 1) {
2043 output_plain(rl_pixel);
2045 DEBUGMSG(("rl_flush ]\n"));
2049 rl_flush_fromclear(rl_count);
2050 } else if ((rl_table_max < 2) || (rl_table_pixel != rl_pixel)) {
2051 rl_flush_clearorrep(rl_count);
2053 rl_flush_withtable(rl_count);
2055 DEBUGMSG(("rl_flush ]\n"));
2061 compress(init_bits, handle, readValue)
2072 code_clear = 1 << (init_bits - 1);
2073 code_eof = code_clear + 1;
2074 rl_basecode = code_eof + 1;
2075 out_bump_init = (1 << (init_bits - 1)) - 1;
2077 * For images with a lot of runs, making out_clear_init larger
2078 * will give better compression.
2080 out_clear_init = (init_bits <= 3) ? 9 : (out_bump_init-1);
2081 #ifdef MIGIF_DEBUGGING_ENVARS
2084 ocienv = getenv("MIGIF_OUT_CLEAR_INIT");
2086 out_clear_init = atoi(ocienv);
2087 DEBUGMSG(("[overriding out_clear_init to %d]\n", out_clear_init));
2091 out_bits_init = init_bits;
2092 max_ocodes = (1 << GIFBITS) - ((1 << (out_bits_init - 1)) + 3);
2098 if ((rl_count > 0) && (c != rl_pixel)) {
2104 if (rl_pixel == c) {
2116 *-----------------------------------------------------------------------
2118 * End of miGIF section - See copyright notice at start of section.
2120 *-----------------------------------------------------------------------