1/*
2 * tkImgGIF.c --
3 *
4 *	A photo image file handler for GIF files. Reads 87a and 89a GIF files.
5 *	At present, there only is a file write function. GIF images may be
6 *	read using the -data option of the photo image. The data may be given
7 *	as a binary string in a Tcl_Obj or by representing the data as BASE64
8 *	encoded ascii. Derived from the giftoppm code found in the pbmplus
9 *	package and tkImgFmtPPM.c in the tk4.0b2 distribution.
10 *
11 * Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee
12 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
13 * Copyright (c) 1997 Australian National University
14 * Copyright (c) 2005 Donal K. Fellows
15 *
16 * See the file "license.terms" for information on usage and redistribution of
17 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 *
19 * This file also contains code from the giftoppm program, which is
20 * copyrighted as follows:
21 *
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 * +--------------------------------------------------------------------+
31 *
32 * This file also contains code from miGIF. See lower down in file for the
33 * applicable copyright notice for that portion.
34 *
35 * RCS: @(#) $Id$
36 */
37
38#include "tkInt.h"
39
40/*
41 * GIF's are represented as data in either binary or base64 format. base64
42 * strings consist of 4 6-bit characters -> 3 8 bit bytes. A-Z, a-z, 0-9, +
43 * and / represent the 64 values (in order). '=' is a trailing padding char
44 * when the un-encoded data is not a multiple of 3 bytes. We'll ignore white
45 * space when encountered. Any other invalid character is treated as an EOF
46 */
47
48#define GIF_SPECIAL	(256)
49#define GIF_PAD		(GIF_SPECIAL+1)
50#define GIF_SPACE	(GIF_SPECIAL+2)
51#define GIF_BAD		(GIF_SPECIAL+3)
52#define GIF_DONE	(GIF_SPECIAL+4)
53
54/*
55 * structure to "mimic" FILE for Mread, so we can look like fread. The decoder
56 * state keeps track of which byte we are about to read, or EOF.
57 */
58
59typedef struct mFile {
60    unsigned char *data;	/* mmencoded source string */
61    int c;			/* bits left over from previous character */
62    int state;			/* decoder state (0-4 or GIF_DONE) */
63    int length;			/* Total amount of bytes in data */
64} MFile;
65
66/*
67 * Non-ASCII encoding support:
68 * Most data in a GIF image is binary and is treated as such. However, a few
69 * key bits are stashed in ASCII. If we try to compare those pieces to the
70 * char they represent, it will fail on any non-ASCII (eg, EBCDIC) system. To
71 * accomodate these systems, we test against the numeric value of the ASCII
72 * characters instead of the characters themselves. This is encoding
73 * independant.
74 */
75
76static const char GIF87a[] = {			/* ASCII GIF87a */
77    0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x00
78};
79static const char GIF89a[] = {			/* ASCII GIF89a */
80    0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x00
81};
82#define GIF_TERMINATOR	0x3b			/* ASCII ; */
83#define GIF_EXTENSION	0x21			/* ASCII ! */
84#define GIF_START	0x2c			/* ASCII , */
85
86/*
87 * Flags used to notify that we've got inline data instead of a file to read
88 * from. Note that we need to figure out which type of inline data we've got
89 * before handing off to the GIF reading code; this is done in StringReadGIF.
90 */
91
92#define INLINE_DATA_BINARY	((const char *) 0x01)
93#define INLINE_DATA_BASE64	((const char *) 0x02)
94
95/*
96 *		HACK ALERT!!  HACK ALERT!!  HACK ALERT!!
97 * This code is hard-wired for reading from files. In order to read from a
98 * data stream, we'll trick fread so we can reuse the same code. 0==from file;
99 * 1==from base64 encoded data; 2==from binary data
100 */
101
102typedef struct {
103    const char *fromData;
104    unsigned char workingBuffer[280];
105    struct {
106	int bytes;
107	int done;
108	unsigned int window;
109	int bitsInWindow;
110	unsigned char *c;
111    } reader;
112} GIFImageConfig;
113
114/*
115 * The format record for the GIF file format:
116 */
117
118static int		FileMatchGIF(Tcl_Channel chan, const char *fileName,
119			    Tcl_Obj *format, int *widthPtr, int *heightPtr,
120			    Tcl_Interp *interp);
121static int		FileReadGIF(Tcl_Interp *interp, Tcl_Channel chan,
122			    const char *fileName, Tcl_Obj *format,
123			    Tk_PhotoHandle imageHandle, int destX, int destY,
124			    int width, int height, int srcX, int srcY);
125static int		StringMatchGIF(Tcl_Obj *dataObj, Tcl_Obj *format,
126			    int *widthPtr, int *heightPtr, Tcl_Interp *interp);
127static int		StringReadGIF(Tcl_Interp *interp, Tcl_Obj *dataObj,
128			    Tcl_Obj *format, Tk_PhotoHandle imageHandle,
129			    int destX, int destY, int width, int height,
130			    int srcX, int srcY);
131static int		FileWriteGIF(Tcl_Interp *interp, const char *filename,
132			    Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr);
133static int		CommonWriteGIF(Tcl_Interp *interp, Tcl_Channel handle,
134			    Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr);
135
136Tk_PhotoImageFormat tkImgFmtGIF = {
137    "gif",		/* name */
138    FileMatchGIF,	/* fileMatchProc */
139    StringMatchGIF,	/* stringMatchProc */
140    FileReadGIF,	/* fileReadProc */
141    StringReadGIF,	/* stringReadProc */
142    FileWriteGIF,	/* fileWriteProc */
143    NULL,		/* stringWriteProc */
144};
145
146#define INTERLACE		0x40
147#define LOCALCOLORMAP		0x80
148#define BitSet(byte, bit)	(((byte) & (bit)) == (bit))
149#define MAXCOLORMAPSIZE		256
150#define CM_RED			0
151#define CM_GREEN		1
152#define CM_BLUE			2
153#define CM_ALPHA		3
154#define MAX_LWZ_BITS		12
155#define LM_to_uint(a,b)		(((b)<<8)|(a))
156
157/*
158 * Prototypes for local functions defined in this file:
159 */
160
161static int		DoExtension(GIFImageConfig *gifConfPtr,
162			    Tcl_Channel chan, int label, unsigned char *buffer,
163			    int *transparent);
164static int		GetCode(Tcl_Channel chan, int code_size, int flag,
165			    GIFImageConfig *gifConfPtr);
166static int		GetDataBlock(GIFImageConfig *gifConfPtr,
167			    Tcl_Channel chan, unsigned char *buf);
168static int		ReadColorMap(GIFImageConfig *gifConfPtr,
169			    Tcl_Channel chan, int number,
170			    unsigned char buffer[MAXCOLORMAPSIZE][4]);
171static int		ReadGIFHeader(GIFImageConfig *gifConfPtr,
172			    Tcl_Channel chan, int *widthPtr, int *heightPtr);
173static int		ReadImage(GIFImageConfig *gifConfPtr,
174			    Tcl_Interp *interp, unsigned char *imagePtr,
175			    Tcl_Channel chan, int len, int rows,
176			    unsigned char cmap[MAXCOLORMAPSIZE][4], int srcX,
177			    int srcY, int interlace, int transparent);
178
179/*
180 * these are for the BASE64 image reader code only
181 */
182
183static int		Fread(GIFImageConfig *gifConfPtr, unsigned char *dst,
184			    size_t size, size_t count, Tcl_Channel chan);
185static int		Mread(unsigned char *dst, size_t size, size_t count,
186			    MFile *handle);
187static int		Mgetc(MFile *handle);
188static int		char64(int c);
189static void		mInit(unsigned char *string, MFile *handle,
190			    int length);
191
192/*
193 *----------------------------------------------------------------------
194 *
195 * FileMatchGIF --
196 *
197 *	This function is invoked by the photo image type to see if a file
198 *	contains image data in GIF format.
199 *
200 * Results:
201 *	The return value is 1 if the first characters in file f look like GIF
202 *	data, and 0 otherwise.
203 *
204 * Side effects:
205 *	The access position in f may change.
206 *
207 *----------------------------------------------------------------------
208 */
209
210static int
211FileMatchGIF(
212    Tcl_Channel chan,		/* The image file, open for reading. */
213    const char *fileName,	/* The name of the image file. */
214    Tcl_Obj *format,		/* User-specified format object, or NULL. */
215    int *widthPtr, int *heightPtr,
216				/* The dimensions of the image are returned
217				 * here if the file is a valid raw GIF file. */
218    Tcl_Interp *interp)		/* not used */
219{
220    GIFImageConfig gifConf;
221
222    memset(&gifConf, 0, sizeof(GIFImageConfig));
223    return ReadGIFHeader(&gifConf, chan, widthPtr, heightPtr);
224}
225
226/*
227 *----------------------------------------------------------------------
228 *
229 * FileReadGIF --
230 *
231 *	This function is called by the photo image type to read GIF format
232 *	data from a file and write it into a given photo image.
233 *
234 * Results:
235 *	A standard TCL completion code. If TCL_ERROR is returned then an error
236 *	message is left in the interp's result.
237 *
238 * Side effects:
239 *	The access position in file f is changed, and new data is added to the
240 *	image given by imageHandle.
241 *
242 *----------------------------------------------------------------------
243 */
244
245static int
246FileReadGIF(
247    Tcl_Interp *interp,		/* Interpreter to use for reporting errors. */
248    Tcl_Channel chan,		/* The image file, open for reading. */
249    const char *fileName,	/* The name of the image file. */
250    Tcl_Obj *format,		/* User-specified format object, or NULL. */
251    Tk_PhotoHandle imageHandle,	/* The photo image to write into. */
252    int destX, int destY,	/* Coordinates of top-left pixel in photo
253				 * image to be written to. */
254    int width, int height,	/* Dimensions of block of photo image to be
255				 * written to. */
256    int srcX, int srcY)		/* Coordinates of top-left pixel to be used in
257				 * image being read. */
258{
259    int fileWidth, fileHeight, imageWidth, imageHeight;
260    int nBytes, index = 0, argc = 0, i, result = TCL_ERROR;
261    Tcl_Obj **objv;
262    unsigned char buf[100];
263    unsigned char *trashBuffer = NULL;
264    int bitPixel;
265    unsigned char colorMap[MAXCOLORMAPSIZE][4];
266    int transparent = -1;
267    static const char *optionStrings[] = {
268	"-index", NULL
269    };
270    GIFImageConfig gifConf, *gifConfPtr = &gifConf;
271
272    /*
273     * Decode the magic used to convey when we're sourcing data from a string
274     * source and not a file.
275     */
276
277    memset(gifConfPtr, 0, sizeof(GIFImageConfig));
278    if (fileName == INLINE_DATA_BINARY || fileName == INLINE_DATA_BASE64) {
279	gifConfPtr->fromData = fileName;
280	fileName = "inline data";
281    }
282
283    /*
284     * Parse the format string to get options.
285     */
286
287    if (format && Tcl_ListObjGetElements(interp, format,
288	    &argc, &objv) != TCL_OK) {
289	return TCL_ERROR;
290    }
291    for (i = 1; i < argc; i++) {
292	if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option name",
293		0, &nBytes) != TCL_OK) {
294	    return TCL_ERROR;
295	}
296	if (i == (argc-1)) {
297	    Tcl_AppendResult(interp, "no value given for \"",
298		    Tcl_GetString(objv[i]), "\" option", NULL);
299	    return TCL_ERROR;
300	}
301	if (Tcl_GetIntFromObj(interp, objv[++i], &index) != TCL_OK) {
302	    return TCL_ERROR;
303	}
304    }
305
306    /*
307     * Read the GIF file header and check for some sanity.
308     */
309
310    if (!ReadGIFHeader(gifConfPtr, chan, &fileWidth, &fileHeight)) {
311	Tcl_AppendResult(interp, "couldn't read GIF header from file \"",
312		fileName, "\"", NULL);
313	return TCL_ERROR;
314    }
315    if ((fileWidth <= 0) || (fileHeight <= 0)) {
316	Tcl_AppendResult(interp, "GIF image file \"", fileName,
317		"\" has dimension(s) <= 0", NULL);
318	return TCL_ERROR;
319    }
320
321    /*
322     * Get the general colormap information.
323     */
324
325    if (Fread(gifConfPtr, buf, 1, 3, chan) != 3) {
326	return TCL_OK;
327    }
328    bitPixel = 2 << (buf[0] & 0x07);
329
330    if (BitSet(buf[0], LOCALCOLORMAP)) {	/* Global Colormap */
331	if (!ReadColorMap(gifConfPtr, chan, bitPixel, colorMap)) {
332	    Tcl_AppendResult(interp, "error reading color map", NULL);
333	    return TCL_ERROR;
334	}
335    }
336
337    if ((srcX + width) > fileWidth) {
338	width = fileWidth - srcX;
339    }
340    if ((srcY + height) > fileHeight) {
341	height = fileHeight - srcY;
342    }
343    if ((width <= 0) || (height <= 0)
344	    || (srcX >= fileWidth) || (srcY >= fileHeight)) {
345	return TCL_OK;
346    }
347
348    /*
349     * Make sure we have enough space in the photo image to hold the data from
350     * the GIF.
351     */
352
353    if (Tk_PhotoExpand(interp, imageHandle,
354	    destX + width, destY + height) != TCL_OK) {
355	return TCL_ERROR;
356    }
357
358    /*
359     * Search for the frame from the GIF to display.
360     */
361
362    while (1) {
363	if (Fread(gifConfPtr, buf, 1, 1, chan) != 1) {
364	    /*
365	     * Premature end of image.
366	     */
367
368	    Tcl_AppendResult(interp,
369		    "premature end of image data for this index", NULL);
370	    goto error;
371	}
372
373	switch (buf[0]) {
374	case GIF_TERMINATOR:
375	    Tcl_AppendResult(interp, "no image data for this index", NULL);
376	    goto error;
377
378	case GIF_EXTENSION:
379	    /*
380	     * This is a GIF extension.
381	     */
382
383	    if (Fread(gifConfPtr, buf, 1, 1, chan) != 1) {
384		Tcl_SetResult(interp,
385			"error reading extension function code in GIF image",
386			TCL_STATIC);
387		goto error;
388	    }
389	    if (DoExtension(gifConfPtr, chan, buf[0],
390		    gifConfPtr->workingBuffer, &transparent) < 0) {
391		Tcl_SetResult(interp, "error reading extension in GIF image",
392			TCL_STATIC);
393		goto error;
394	    }
395	    continue;
396	case GIF_START:
397	    if (Fread(gifConfPtr, buf, 1, 9, chan) != 9) {
398		Tcl_SetResult(interp,
399			"couldn't read left/top/width/height in GIF image",
400			TCL_STATIC);
401		goto error;
402	    }
403	    break;
404	default:
405	    /*
406	     * Not a valid start character; ignore it.
407	     */
408
409	    continue;
410	}
411
412	/*
413	 * We've read the header for a GIF frame. Work out what we are going
414	 * to do about it.
415	 */
416
417	imageWidth = LM_to_uint(buf[4], buf[5]);
418	imageHeight = LM_to_uint(buf[6], buf[7]);
419	bitPixel = 1 << ((buf[8] & 0x07) + 1);
420
421	if (index--) {
422	    /*
423	     * This is not the GIF frame we want to read: skip it.
424	     */
425
426	    if (BitSet(buf[8], LOCALCOLORMAP)) {
427		if (!ReadColorMap(gifConfPtr, chan, bitPixel, colorMap)) {
428		    Tcl_AppendResult(interp, "error reading color map", NULL);
429		    goto error;
430		}
431	    }
432
433	    /*
434	     * If we've not yet allocated a trash buffer, do so now.
435	     */
436
437	    if (trashBuffer == NULL) {
438		nBytes = fileWidth * fileHeight * 3;
439		trashBuffer = (unsigned char *) ckalloc((unsigned) nBytes);
440	    }
441
442	    /*
443	     * Slurp! Process the data for this image and stuff it in a trash
444	     * buffer.
445	     *
446	     * Yes, it might be more efficient here to *not* store the data
447	     * (we're just going to throw it away later). However, I elected
448	     * to implement it this way for good reasons. First, I wanted to
449	     * avoid duplicating the (fairly complex) LWZ decoder in
450	     * ReadImage. Fine, you say, why didn't you just modify it to
451	     * allow the use of a NULL specifier for the output buffer? I
452	     * tried that, but it negatively impacted the performance of what
453	     * I think will be the common case: reading the first image in the
454	     * file. Rather than marginally improve the speed of the less
455	     * frequent case, I chose to maintain high performance for the
456	     * common case.
457	     */
458
459	    if (ReadImage(gifConfPtr, interp, trashBuffer, chan, imageWidth,
460		    imageHeight, colorMap, 0, 0, 0, -1) != TCL_OK) {
461		goto error;
462	    }
463	    continue;
464	}
465	break;
466    }
467
468    /*
469     * Found the frame we want to read. Next, check for a local color map for
470     * this frame.
471     */
472
473    if (BitSet(buf[8], LOCALCOLORMAP)) {
474	if (!ReadColorMap(gifConfPtr, chan, bitPixel, colorMap)) {
475	    Tcl_AppendResult(interp, "error reading color map", NULL);
476	    goto error;
477	}
478    }
479
480    /*
481     * Extract the location within the overall visible image to put the data
482     * in this frame, together with the size of this frame.
483     */
484
485    index = LM_to_uint(buf[0], buf[1]);
486    srcX -= index;
487    if (srcX<0) {
488	destX -= srcX; width += srcX;
489	srcX = 0;
490    }
491
492    if (width > imageWidth) {
493	width = imageWidth;
494    }
495
496    index = LM_to_uint(buf[2], buf[3]);
497    srcY -= index;
498    if (index > srcY) {
499	destY -= srcY; height += srcY;
500	srcY = 0;
501    }
502    if (height > imageHeight) {
503	height = imageHeight;
504    }
505
506    if ((width > 0) && (height > 0)) {
507	Tk_PhotoImageBlock block;
508
509	/*
510	 * Read the data and put it into the photo buffer for display by the
511	 * general image machinery.
512	 */
513
514	block.width = width;
515	block.height = height;
516	block.pixelSize = (transparent>=0) ? 4 : 3;
517	block.offset[0] = 0;
518	block.offset[1] = 1;
519	block.offset[2] = 2;
520	block.offset[3] = (transparent>=0) ? 3 : 0;
521	block.pitch = block.pixelSize * imageWidth;
522	nBytes = block.pitch * imageHeight;
523	block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
524
525	if (ReadImage(gifConfPtr, interp, block.pixelPtr, chan, imageWidth,
526		imageHeight, colorMap, srcX, srcY, BitSet(buf[8],INTERLACE),
527		transparent) != TCL_OK) {
528	    ckfree((char *) block.pixelPtr);
529	    goto error;
530	}
531	if (Tk_PhotoPutBlock(interp, imageHandle, &block, destX, destY,
532		width, height, TK_PHOTO_COMPOSITE_SET) != TCL_OK) {
533	    ckfree((char *) block.pixelPtr);
534	    goto error;
535	}
536	ckfree((char *) block.pixelPtr);
537    }
538
539    /*
540     * We've successfully read the GIF frame (or there was nothing to read,
541     * which suits as well). We're done.
542     */
543
544    Tcl_AppendResult(interp, tkImgFmtGIF.name, NULL);
545    result = TCL_OK;
546
547  error:
548    /*
549     * If a trash buffer has been allocated, free it now.
550     */
551
552    if (trashBuffer != NULL) {
553	ckfree((char *) trashBuffer);
554    }
555    return result;
556}
557
558/*
559 *----------------------------------------------------------------------
560 *
561 * StringMatchGIF --
562 *
563 *	This function is invoked by the photo image type to see if an object
564 *	contains image data in GIF format.
565 *
566 * Results:
567 *	The return value is 1 if the first characters in the data are like GIF
568 *	data, and 0 otherwise.
569 *
570 * Side effects:
571 *	The size of the image is placed in widthPtr and heightPtr.
572 *
573 *----------------------------------------------------------------------
574 */
575
576static int
577StringMatchGIF(
578    Tcl_Obj *dataObj,		/* the object containing the image data */
579    Tcl_Obj *format,		/* the image format object, or NULL */
580    int *widthPtr,		/* where to put the string width */
581    int *heightPtr,		/* where to put the string height */
582    Tcl_Interp *interp)		/* not used */
583{
584    unsigned char *data, header[10];
585    int got, length;
586    MFile handle;
587
588    data = Tcl_GetByteArrayFromObj(dataObj, &length);
589
590    /*
591     * Header is a minimum of 10 bytes.
592     */
593
594    if (length < 10) {
595	return 0;
596    }
597
598    /*
599     * Check whether the data is Base64 encoded.
600     */
601
602    if ((strncmp(GIF87a, (char *) data, 6) != 0) &&
603	    (strncmp(GIF89a, (char *) data, 6) != 0)) {
604	/*
605	 * Try interpreting the data as Base64 encoded
606	 */
607
608	mInit((unsigned char *) data, &handle, length);
609	got = Mread(header, 10, 1, &handle);
610	if (got != 10 ||
611		((strncmp(GIF87a, (char *) header, 6) != 0)
612		&& (strncmp(GIF89a, (char *) header, 6) != 0))) {
613	    return 0;
614	}
615    } else {
616	memcpy(header, data, 10);
617    }
618    *widthPtr = LM_to_uint(header[6], header[7]);
619    *heightPtr = LM_to_uint(header[8], header[9]);
620    return 1;
621}
622
623/*
624 *----------------------------------------------------------------------
625 *
626 * StringReadGIF --
627 *
628 *	This function is called by the photo image type to read GIF format
629 *	data from an object, optionally base64 encoded, and give it to the
630 *	photo image.
631 *
632 * Results:
633 *	A standard TCL completion code. If TCL_ERROR is returned then an error
634 *	message is left in the interp's result.
635 *
636 * Side effects:
637 *	New data is added to the image given by imageHandle. This function
638 *	calls FileReadGIF by redefining the operation of fprintf temporarily.
639 *
640 *----------------------------------------------------------------------
641 */
642
643static int
644StringReadGIF(
645    Tcl_Interp *interp,		/* interpreter for reporting errors in */
646    Tcl_Obj *dataObj,		/* object containing the image */
647    Tcl_Obj *format,		/* format object, or NULL */
648    Tk_PhotoHandle imageHandle,	/* the image to write this data into */
649    int destX, int destY,	/* The rectangular region of the */
650    int width, int height,	/* image to copy */
651    int srcX, int srcY)
652{
653    MFile handle, *hdlPtr = &handle;
654    int length;
655    const char *xferFormat;
656    unsigned char *data = Tcl_GetByteArrayFromObj(dataObj, &length);
657
658    mInit(data, hdlPtr, length);
659
660    /*
661     * Check whether the data is Base64 encoded by doing a character-by-
662     * charcter comparison with the binary-format headers; BASE64-encoded
663     * never matches (matching the other way is harder because of potential
664     * padding of the BASE64 data).
665     */
666
667    if (strncmp(GIF87a, (char *) data, 6)
668	    && strncmp(GIF89a, (char *) data, 6)) {
669	xferFormat = INLINE_DATA_BASE64;
670    } else {
671	xferFormat = INLINE_DATA_BINARY;
672    }
673
674    /*
675     * Fall through to the file reader now that we have a correctly-configured
676     * pseudo-channel to pull the data from.
677     */
678
679    return FileReadGIF(interp, (Tcl_Channel) hdlPtr, xferFormat, format,
680	    imageHandle, destX, destY, width, height, srcX, srcY);
681}
682
683/*
684 *----------------------------------------------------------------------
685 *
686 * ReadGIFHeader --
687 *
688 *	This function reads the GIF header from the beginning of a GIF file
689 *	and returns the dimensions of the image.
690 *
691 * Results:
692 *	The return value is 1 if file "f" appears to start with a valid GIF
693 *	header, 0 otherwise. If the header is valid, then *widthPtr and
694 *	*heightPtr are modified to hold the dimensions of the image.
695 *
696 * Side effects:
697 *	The access position in f advances.
698 *
699 *----------------------------------------------------------------------
700 */
701
702static int
703ReadGIFHeader(
704    GIFImageConfig *gifConfPtr,
705    Tcl_Channel chan,		/* Image file to read the header from */
706    int *widthPtr, int *heightPtr)
707				/* The dimensions of the image are returned
708				 * here. */
709{
710    unsigned char buf[7];
711
712    if ((Fread(gifConfPtr, buf, 1, 6, chan) != 6)
713	    || ((strncmp(GIF87a, (char *) buf, 6) != 0)
714	    && (strncmp(GIF89a, (char *) buf, 6) != 0))) {
715	return 0;
716    }
717
718    if (Fread(gifConfPtr, buf, 1, 4, chan) != 4) {
719	return 0;
720    }
721
722    *widthPtr = LM_to_uint(buf[0], buf[1]);
723    *heightPtr = LM_to_uint(buf[2], buf[3]);
724    return 1;
725}
726
727/*
728 *-----------------------------------------------------------------
729 * The code below is copied from the giftoppm program and modified just
730 * slightly.
731 *-----------------------------------------------------------------
732 */
733
734static int
735ReadColorMap(
736    GIFImageConfig *gifConfPtr,
737    Tcl_Channel chan,
738    int number,
739    unsigned char buffer[MAXCOLORMAPSIZE][4])
740{
741    int i;
742    unsigned char rgb[3];
743
744    for (i = 0; i < number; ++i) {
745	if (Fread(gifConfPtr, rgb, sizeof(rgb), 1, chan) <= 0) {
746	    return 0;
747	}
748
749	if (buffer) {
750	    buffer[i][CM_RED] = rgb[0];
751	    buffer[i][CM_GREEN] = rgb[1];
752	    buffer[i][CM_BLUE] = rgb[2];
753	    buffer[i][CM_ALPHA] = 255;
754	}
755    }
756    return 1;
757}
758
759static int
760DoExtension(
761    GIFImageConfig *gifConfPtr,
762    Tcl_Channel chan,
763    int label,
764    unsigned char *buf,
765    int *transparent)
766{
767    int count;
768
769    switch (label) {
770    case 0x01:		/* Plain Text Extension */
771	break;
772
773    case 0xff:		/* Application Extension */
774	break;
775
776    case 0xfe:		/* Comment Extension */
777	do {
778	    count = GetDataBlock(gifConfPtr, chan, buf);
779	} while (count > 0);
780	return count;
781
782    case 0xf9:		/* Graphic Control Extension */
783	count = GetDataBlock(gifConfPtr, chan, buf);
784	if (count < 0) {
785	    return 1;
786	}
787	if ((buf[0] & 0x1) != 0) {
788	    *transparent = buf[3];
789	}
790
791	do {
792	    count = GetDataBlock(gifConfPtr, chan, buf);
793	} while (count > 0);
794	return count;
795    }
796
797    do {
798	count = GetDataBlock(gifConfPtr, chan, buf);
799    } while (count > 0);
800    return count;
801}
802
803static int
804GetDataBlock(
805    GIFImageConfig *gifConfPtr,
806    Tcl_Channel chan,
807    unsigned char *buf)
808{
809    unsigned char count;
810
811    if (Fread(gifConfPtr, &count, 1, 1, chan) <= 0) {
812	return -1;
813    }
814
815    if ((count != 0) && (Fread(gifConfPtr, buf, count, 1, chan) <= 0)) {
816	return -1;
817    }
818
819    return count;
820}
821
822/*
823 *----------------------------------------------------------------------
824 *
825 * ReadImage --
826 *
827 *	Process a GIF image from a given source, with a given height, width,
828 *	transparency, etc.
829 *
830 *	This code is based on the code found in the ImageMagick GIF decoder,
831 *	which is (c) 2000 ImageMagick Studio.
832 *
833 *	Some thoughts on our implementation:
834 *	It sure would be nice if ReadImage didn't take 11 parameters! I think
835 *	that if we were smarter, we could avoid doing that.
836 *
837 *	Possible further optimizations: we could pull the GetCode function
838 *	directly into ReadImage, which would improve our speed.
839 *
840 * Results:
841 *	Processes a GIF image and loads the pixel data into a memory array.
842 *
843 * Side effects:
844 *	None.
845 *
846 *----------------------------------------------------------------------
847 */
848
849static int
850ReadImage(
851    GIFImageConfig *gifConfPtr,
852    Tcl_Interp *interp,
853    unsigned char *imagePtr,
854    Tcl_Channel chan,
855    int len, int rows,
856    unsigned char cmap[MAXCOLORMAPSIZE][4],
857    int srcX, int srcY,
858    int interlace,
859    int transparent)
860{
861    unsigned char initialCodeSize;
862    int xpos = 0, ypos = 0, pass = 0, i;
863    register unsigned char *pixelPtr;
864    static const int interlaceStep[] = { 8, 8, 4, 2 };
865    static const int interlaceStart[] = { 0, 4, 2, 1 };
866    unsigned short prefix[(1 << MAX_LWZ_BITS)];
867    unsigned char append[(1 << MAX_LWZ_BITS)];
868    unsigned char stack[(1 << MAX_LWZ_BITS)*2];
869    register unsigned char *top;
870    int codeSize, clearCode, inCode, endCode, oldCode, maxCode;
871    int code, firstCode, v;
872
873    /*
874     * Initialize the decoder
875     */
876
877    if (Fread(gifConfPtr, &initialCodeSize, 1, 1, chan) <= 0) {
878	Tcl_AppendResult(interp, "error reading GIF image: ",
879		Tcl_PosixError(interp), NULL);
880	return TCL_ERROR;
881    }
882
883    if (initialCodeSize > MAX_LWZ_BITS) {
884	Tcl_SetResult(interp, "malformed image", TCL_STATIC);
885	return TCL_ERROR;
886    }
887
888    if (transparent != -1) {
889	cmap[transparent][CM_RED] = 0;
890	cmap[transparent][CM_GREEN] = 0;
891	cmap[transparent][CM_BLUE] = 0;
892	cmap[transparent][CM_ALPHA] = 0;
893    }
894
895    pixelPtr = imagePtr;
896
897    /*
898     * Initialize the decoder.
899     *
900     * Set values for "special" numbers:
901     * clear code	reset the decoder
902     * end code		stop decoding
903     * code size	size of the next code to retrieve
904     * max code		next available table position
905     */
906
907    clearCode = 1 << (int) initialCodeSize;
908    endCode = clearCode + 1;
909    codeSize = (int) initialCodeSize + 1;
910    maxCode = clearCode + 2;
911    oldCode = -1;
912    firstCode = -1;
913
914    memset(prefix, 0, (1 << MAX_LWZ_BITS) * sizeof(short));
915    memset(append, 0, (1 << MAX_LWZ_BITS) * sizeof(char));
916    for (i = 0; i < clearCode; i++) {
917	append[i] = i;
918    }
919    top = stack;
920
921    GetCode(chan, 0, 1, gifConfPtr);
922
923    /*
924     * Read until we finish the image
925     */
926
927    for (i = 0, ypos = 0; i < rows; i++) {
928	for (xpos = 0; xpos < len; ) {
929	    if (top == stack) {
930		/*
931		 * Bummer - our stack is empty. Now we have to work!
932		 */
933
934		code = GetCode(chan, codeSize, 0, gifConfPtr);
935		if (code < 0) {
936		    return TCL_OK;
937		}
938
939		if (code > maxCode || code == endCode) {
940		    /*
941		     * If we're doing things right, we should never receive a
942		     * code that is greater than our current maximum code. If
943		     * we do, bail, because our decoder does not yet have that
944		     * code set up.
945		     *
946		     * If the code is the magic endCode value, quit.
947		     */
948
949		    return TCL_OK;
950		}
951
952		if (code == clearCode) {
953		    /*
954		     * Reset the decoder.
955		     */
956
957		    codeSize = initialCodeSize + 1;
958		    maxCode = clearCode + 2;
959		    oldCode = -1;
960		    continue;
961		}
962
963		if (oldCode == -1) {
964		    /*
965		     * Last pass reset the decoder, so the first code we see
966		     * must be a singleton. Seed the stack with it, and set up
967		     * the old/first code pointers for insertion into the
968		     * string table. We can't just roll this into the
969		     * clearCode test above, because at that point we have not
970		     * yet read the next code.
971		     */
972
973		    *top++ = append[code];
974		    oldCode = code;
975		    firstCode = code;
976		    continue;
977		}
978
979		inCode = code;
980
981		if (code == maxCode) {
982		    /*
983		     * maxCode is always one bigger than our highest assigned
984		     * code. If the code we see is equal to maxCode, then we
985		     * are about to add a new string to the table. ???
986		     */
987
988		    *top++ = firstCode;
989		    code = oldCode;
990		}
991
992		while (code > clearCode) {
993		    /*
994		     * Populate the stack by tracing the string in the string
995		     * table from its tail to its head
996		     */
997
998		    *top++ = append[code];
999		    code = prefix[code];
1000		}
1001		firstCode = append[code];
1002
1003		/*
1004		 * If there's no more room in our string table, quit.
1005		 * Otherwise, add a new string to the table
1006		 */
1007
1008		if (maxCode >= (1 << MAX_LWZ_BITS)) {
1009		    return TCL_OK;
1010		}
1011
1012		/*
1013		 * Push the head of the string onto the stack.
1014		 */
1015
1016		*top++ = firstCode;
1017
1018		/*
1019		 * Add a new string to the string table
1020		 */
1021
1022		prefix[maxCode] = oldCode;
1023		append[maxCode] = firstCode;
1024		maxCode++;
1025
1026		/*
1027		 * maxCode tells us the maximum code value we can accept. If
1028		 * we see that we need more bits to represent it than we are
1029		 * requesting from the unpacker, we need to increase the
1030		 * number we ask for.
1031		 */
1032
1033		if ((maxCode >= (1 << codeSize))
1034			&& (maxCode < (1<<MAX_LWZ_BITS))) {
1035		    codeSize++;
1036		}
1037		oldCode = inCode;
1038	    }
1039
1040	    /*
1041	     * Pop the next color index off the stack.
1042	     */
1043
1044	    v = *(--top);
1045	    if (v < 0) {
1046		return TCL_OK;
1047	    }
1048
1049	    /*
1050	     * If pixelPtr is null, we're skipping this image (presumably
1051	     * there are more in the file and we will be called to read one of
1052	     * them later)
1053	     */
1054
1055	    *pixelPtr++ = cmap[v][CM_RED];
1056	    *pixelPtr++ = cmap[v][CM_GREEN];
1057	    *pixelPtr++ = cmap[v][CM_BLUE];
1058	    if (transparent >= 0) {
1059		*pixelPtr++ = cmap[v][CM_ALPHA];
1060	    }
1061	    xpos++;
1062
1063	}
1064
1065	/*
1066	 * If interlacing, the next ypos is not just +1.
1067	 */
1068
1069	if (interlace) {
1070	    ypos += interlaceStep[pass];
1071	    while (ypos >= rows) {
1072		pass++;
1073		if (pass > 3) {
1074		    return TCL_OK;
1075		}
1076		ypos = interlaceStart[pass];
1077	    }
1078	} else {
1079	    ypos++;
1080	}
1081	pixelPtr = imagePtr + (ypos) * len * ((transparent>=0)?4:3);
1082    }
1083    return TCL_OK;
1084}
1085
1086/*
1087 *----------------------------------------------------------------------
1088 *
1089 * GetCode --
1090 *
1091 *	Extract the next compression code from the file. In GIF's, the
1092 *	compression codes are between 3 and 12 bits long and are then packed
1093 *	into 8 bit bytes, left to right, for example:
1094 *		bbbaaaaa
1095 *		dcccccbb
1096 *		eeeedddd
1097 *		...
1098 *	We use a byte buffer read from the file and a sliding window to unpack
1099 *	the bytes. Thanks to ImageMagick for the sliding window idea.
1100 *	args:  chan	    the channel to read from
1101 *	       code_size    size of the code to extract
1102 *	       flag	    boolean indicating whether the extractor should be
1103 *			    reset or not
1104 *
1105 * Results:
1106 *	code		    the next compression code
1107 *
1108 * Side effects:
1109 *	May consume more input from chan.
1110 *
1111 *----------------------------------------------------------------------
1112 */
1113
1114static int
1115GetCode(
1116    Tcl_Channel chan,
1117    int code_size,
1118    int flag,
1119    GIFImageConfig *gifConfPtr)
1120{
1121    int ret;
1122
1123    if (flag) {
1124	/*
1125	 * Initialize the decoder.
1126	 */
1127
1128	gifConfPtr->reader.bitsInWindow = 0;
1129	gifConfPtr->reader.bytes = 0;
1130	gifConfPtr->reader.window = 0;
1131	gifConfPtr->reader.done = 0;
1132	gifConfPtr->reader.c = NULL;
1133	return 0;
1134    }
1135
1136    while (gifConfPtr->reader.bitsInWindow < code_size) {
1137	/*
1138	 * Not enough bits in our window to cover the request.
1139	 */
1140
1141	if (gifConfPtr->reader.done) {
1142	    return -1;
1143	}
1144	if (gifConfPtr->reader.bytes == 0) {
1145	    /*
1146	     * Not enough bytes in our buffer to add to the window.
1147	     */
1148
1149	    gifConfPtr->reader.bytes =
1150		    GetDataBlock(gifConfPtr, chan, gifConfPtr->workingBuffer);
1151	    gifConfPtr->reader.c = gifConfPtr->workingBuffer;
1152	    if (gifConfPtr->reader.bytes <= 0) {
1153		gifConfPtr->reader.done = 1;
1154		break;
1155	    }
1156	}
1157
1158	/*
1159	 * Tack another byte onto the window, see if that's enough.
1160	 */
1161
1162	gifConfPtr->reader.window +=
1163		(*gifConfPtr->reader.c) << gifConfPtr->reader.bitsInWindow;
1164	gifConfPtr->reader.c++;
1165	gifConfPtr->reader.bitsInWindow += 8;
1166	gifConfPtr->reader.bytes--;
1167    }
1168
1169    /*
1170     * The next code will always be the last code_size bits of the window.
1171     */
1172
1173    ret = gifConfPtr->reader.window & ((1 << code_size) - 1);
1174
1175    /*
1176     * Shift data in the window to put the next code at the end.
1177     */
1178
1179    gifConfPtr->reader.window >>= code_size;
1180    gifConfPtr->reader.bitsInWindow -= code_size;
1181    return ret;
1182}
1183
1184/*
1185 *----------------------------------------------------------------------
1186 *
1187 * Minit -- --
1188 *
1189 *	This function initializes a base64 decoder handle
1190 *
1191 * Results:
1192 *	None
1193 *
1194 * Side effects:
1195 *	The base64 handle is initialized
1196 *
1197 *----------------------------------------------------------------------
1198 */
1199
1200static void
1201mInit(
1202    unsigned char *string,	/* string containing initial mmencoded data */
1203    MFile *handle,		/* mmdecode "file" handle */
1204    int length)			/* Number of bytes in string */
1205{
1206    handle->data = string;
1207    handle->state = 0;
1208    handle->c = 0;
1209    handle->length = length;
1210}
1211
1212/*
1213 *----------------------------------------------------------------------
1214 *
1215 * Mread --
1216 *
1217 *	This function is invoked by the GIF file reader as a temporary
1218 *	replacement for "fread", to get GIF data out of a string (using
1219 *	Mgetc).
1220 *
1221 * Results:
1222 *	The return value is the number of characters "read"
1223 *
1224 * Side effects:
1225 *	The base64 handle will change state.
1226 *
1227 *----------------------------------------------------------------------
1228 */
1229
1230static int
1231Mread(
1232    unsigned char *dst,		/* where to put the result */
1233    size_t chunkSize,		/* size of each transfer */
1234    size_t numChunks,		/* number of chunks */
1235    MFile *handle)		/* mmdecode "file" handle */
1236{
1237    register int i, c;
1238    int count = chunkSize * numChunks;
1239
1240    for (i=0; i<count && (c=Mgetc(handle)) != GIF_DONE; i++) {
1241	*dst++ = c;
1242    }
1243    return i;
1244}
1245
1246/*
1247 *----------------------------------------------------------------------
1248 *
1249 * Mgetc --
1250 *
1251 *	This function gets the next decoded character from an mmencode handle.
1252 *	This causes at least 1 character to be "read" from the encoded string.
1253 *
1254 * Results:
1255 *	The next byte (or GIF_DONE) is returned.
1256 *
1257 * Side effects:
1258 *	The base64 handle will change state.
1259 *
1260 *----------------------------------------------------------------------
1261 */
1262
1263static int
1264Mgetc(
1265    MFile *handle)		/* Handle containing decoder data and state */
1266{
1267    int c;
1268    int result = 0;		/* Initialization needed only to prevent gcc
1269				 * compiler warning. */
1270
1271    if (handle->state == GIF_DONE) {
1272	return GIF_DONE;
1273    }
1274
1275    do {
1276	if (handle->length-- <= 0) {
1277	    return GIF_DONE;
1278	}
1279	c = char64(*handle->data);
1280	handle->data++;
1281    } while (c == GIF_SPACE);
1282
1283    if (c>GIF_SPECIAL) {
1284	handle->state = GIF_DONE;
1285	return handle->c;
1286    }
1287
1288    switch (handle->state++) {
1289    case 0:
1290	handle->c = c<<2;
1291	result = Mgetc(handle);
1292	break;
1293    case 1:
1294	result = handle->c | (c>>4);
1295	handle->c = (c&0xF)<<4;
1296	break;
1297    case 2:
1298	result = handle->c | (c>>2);
1299	handle->c = (c&0x3) << 6;
1300	break;
1301    case 3:
1302	result = handle->c | c;
1303	handle->state = 0;
1304	break;
1305    }
1306    return result;
1307}
1308
1309/*
1310 *----------------------------------------------------------------------
1311 *
1312 * char64 --
1313 *
1314 *	This function converts a base64 ascii character into its binary
1315 *	equivalent. This code is a slightly modified version of the char64
1316 *	function in N. Borenstein's metamail decoder.
1317 *
1318 * Results:
1319 *	The binary value, or an error code.
1320 *
1321 * Side effects:
1322 *	None.
1323 *
1324 *----------------------------------------------------------------------
1325 */
1326
1327static int
1328char64(
1329    int c)
1330{
1331    switch(c) {
1332    case 'A': return 0;  case 'B': return 1;  case 'C': return 2;
1333    case 'D': return 3;  case 'E': return 4;  case 'F': return 5;
1334    case 'G': return 6;  case 'H': return 7;  case 'I': return 8;
1335    case 'J': return 9;  case 'K': return 10; case 'L': return 11;
1336    case 'M': return 12; case 'N': return 13; case 'O': return 14;
1337    case 'P': return 15; case 'Q': return 16; case 'R': return 17;
1338    case 'S': return 18; case 'T': return 19; case 'U': return 20;
1339    case 'V': return 21; case 'W': return 22; case 'X': return 23;
1340    case 'Y': return 24; case 'Z': return 25; case 'a': return 26;
1341    case 'b': return 27; case 'c': return 28; case 'd': return 29;
1342    case 'e': return 30; case 'f': return 31; case 'g': return 32;
1343    case 'h': return 33; case 'i': return 34; case 'j': return 35;
1344    case 'k': return 36; case 'l': return 37; case 'm': return 38;
1345    case 'n': return 39; case 'o': return 40; case 'p': return 41;
1346    case 'q': return 42; case 'r': return 43; case 's': return 44;
1347    case 't': return 45; case 'u': return 46; case 'v': return 47;
1348    case 'w': return 48; case 'x': return 49; case 'y': return 50;
1349    case 'z': return 51; case '0': return 52; case '1': return 53;
1350    case '2': return 54; case '3': return 55; case '4': return 56;
1351    case '5': return 57; case '6': return 58; case '7': return 59;
1352    case '8': return 60; case '9': return 61; case '+': return 62;
1353    case '/': return 63;
1354
1355    case ' ': case '\t': case '\n': case '\r': case '\f':
1356	return GIF_SPACE;
1357    case '=':
1358	return GIF_PAD;
1359    case '\0':
1360	return GIF_DONE;
1361    default:
1362	return GIF_BAD;
1363    }
1364}
1365
1366/*
1367 *----------------------------------------------------------------------
1368 *
1369 * Fread --
1370 *
1371 *	This function calls either fread or Mread to read data from a file or
1372 *	a base64 encoded string.
1373 *
1374 * Results: - same as POSIX fread() or Tcl Tcl_Read()
1375 *
1376 *----------------------------------------------------------------------
1377 */
1378
1379static int
1380Fread(
1381    GIFImageConfig *gifConfPtr,
1382    unsigned char *dst,		/* where to put the result */
1383    size_t hunk, size_t count,	/* how many */
1384    Tcl_Channel chan)
1385{
1386    if (gifConfPtr->fromData == INLINE_DATA_BASE64) {
1387	return Mread(dst, hunk, count, (MFile *) chan);
1388    }
1389
1390    if (gifConfPtr->fromData == INLINE_DATA_BINARY) {
1391	MFile *handle = (MFile *) chan;
1392
1393	if (handle->length <= 0 || (size_t) handle->length < hunk*count) {
1394	    return -1;
1395	}
1396	memcpy(dst, handle->data, (size_t) (hunk * count));
1397	handle->data += hunk * count;
1398	return (int)(hunk * count);
1399    }
1400
1401    /*
1402     * Otherwise we've got a real file to read.
1403     */
1404
1405    return Tcl_Read(chan, (char *) dst, (int) (hunk * count));
1406}
1407
1408/*
1409 * ChanWriteGIF - writes a image in GIF format.
1410 *-------------------------------------------------------------------------
1411 * Author:		Lolo
1412 *			Engeneering Projects Area
1413 *			Department of Mining
1414 *			University of Oviedo
1415 * e-mail		zz11425958@zeus.etsimo.uniovi.es
1416 *			lolo@pcsig22.etsimo.uniovi.es
1417 * Date:		Fri September 20 1996
1418 *
1419 * Modified for transparency handling (gif89a) and miGIF compression
1420 * by Jan Nijtmans <j.nijtmans@chello.nl>
1421 *
1422 *----------------------------------------------------------------------
1423 * FileWriteGIF-
1424 *
1425 *	This function is called by the photo image type to write GIF format
1426 *	data from a photo image into a given file
1427 *
1428 * Results:
1429 *	A standard TCL completion code. If TCL_ERROR is returned then an error
1430 *	message is left in interp->result.
1431 *
1432 *----------------------------------------------------------------------
1433 */
1434
1435/*
1436 * Types, defines and variables needed to write and compress a GIF.
1437 */
1438
1439typedef int (* ifunptr) (ClientData clientData);
1440
1441#define LSB(a)		((unsigned char) (((short)(a)) & 0x00FF))
1442#define MSB(a)		((unsigned char) (((short)(a)) >> 8))
1443
1444#define GIFBITS		12
1445#define HSIZE		5003	/* 80% occupancy */
1446
1447typedef struct {
1448    int ssize;
1449    int csize;
1450    int rsize;
1451    unsigned char *pixelo;
1452    int pixelSize;
1453    int pixelPitch;
1454    int greenOffset;
1455    int blueOffset;
1456    int alphaOffset;
1457    int num;
1458    unsigned char mapa[MAXCOLORMAPSIZE][3];
1459} GifWriterState;
1460
1461/*
1462 * Definition of new functions to write GIFs
1463 */
1464
1465static int		color(GifWriterState *statePtr,
1466			    int red, int green, int blue,
1467			    unsigned char mapa[MAXCOLORMAPSIZE][3]);
1468static void		compress(int initBits, Tcl_Channel handle,
1469			    ifunptr readValue, ClientData clientData);
1470static int		nuevo(GifWriterState *statePtr,
1471			    int red, int green, int blue,
1472			    unsigned char mapa[MAXCOLORMAPSIZE][3]);
1473static void		savemap(GifWriterState *statePtr,
1474			    Tk_PhotoImageBlock *blockPtr,
1475			    unsigned char mapa[MAXCOLORMAPSIZE][3]);
1476static int		ReadValue(ClientData clientData);
1477
1478static int
1479FileWriteGIF(
1480    Tcl_Interp *interp,		/* Interpreter to use for reporting errors. */
1481    const char *filename,
1482    Tcl_Obj *format,
1483    Tk_PhotoImageBlock *blockPtr)
1484{
1485    Tcl_Channel chan = NULL;
1486    int result;
1487
1488    chan = Tcl_OpenFileChannel(interp, (char *) filename, "w", 0644);
1489    if (!chan) {
1490	return TCL_ERROR;
1491    }
1492    if (Tcl_SetChannelOption(interp, chan, "-translation",
1493	    "binary") != TCL_OK) {
1494	Tcl_Close(NULL, chan);
1495	return TCL_ERROR;
1496    }
1497
1498    result = CommonWriteGIF(interp, chan, format, blockPtr);
1499
1500    if (Tcl_Close(interp, chan) == TCL_ERROR) {
1501	return TCL_ERROR;
1502    }
1503    return result;
1504}
1505
1506static int
1507CommonWriteGIF(
1508    Tcl_Interp *interp,
1509    Tcl_Channel handle,
1510    Tcl_Obj *format,
1511    Tk_PhotoImageBlock *blockPtr)
1512{
1513    GifWriterState state, *statePtr = &state;
1514    int resolution;
1515    long width, height, x;
1516    unsigned char c;
1517    unsigned int top, left;
1518
1519    top = 0;
1520    left = 0;
1521
1522    memset(statePtr, 0, sizeof(state));
1523
1524    statePtr->pixelSize = blockPtr->pixelSize;
1525    statePtr->greenOffset = blockPtr->offset[1]-blockPtr->offset[0];
1526    statePtr->blueOffset = blockPtr->offset[2]-blockPtr->offset[0];
1527    statePtr->alphaOffset = blockPtr->offset[0];
1528    if (statePtr->alphaOffset < blockPtr->offset[2]) {
1529	statePtr->alphaOffset = blockPtr->offset[2];
1530    }
1531    if (++statePtr->alphaOffset < statePtr->pixelSize) {
1532	statePtr->alphaOffset -= blockPtr->offset[0];
1533    } else {
1534	statePtr->alphaOffset = 0;
1535    }
1536
1537    Tcl_Write(handle, (char *) (statePtr->alphaOffset ? GIF89a : GIF87a), 6);
1538
1539    for (x=0 ; x<MAXCOLORMAPSIZE ; x++) {
1540	statePtr->mapa[x][CM_RED] = 255;
1541	statePtr->mapa[x][CM_GREEN] = 255;
1542	statePtr->mapa[x][CM_BLUE] = 255;
1543    }
1544
1545    width = blockPtr->width;
1546    height = blockPtr->height;
1547    statePtr->pixelo = blockPtr->pixelPtr + blockPtr->offset[0];
1548    statePtr->pixelPitch = blockPtr->pitch;
1549    savemap(statePtr, blockPtr, statePtr->mapa);
1550    if (statePtr->num >= MAXCOLORMAPSIZE) {
1551	Tcl_AppendResult(interp, "too many colors", NULL);
1552	return TCL_ERROR;
1553    }
1554    if (statePtr->num<2) {
1555	statePtr->num = 2;
1556    }
1557    c = LSB(width);
1558    Tcl_Write(handle, (char *) &c, 1);
1559    c = MSB(width);
1560    Tcl_Write(handle, (char *) &c, 1);
1561    c = LSB(height);
1562    Tcl_Write(handle, (char *) &c, 1);
1563    c = MSB(height);
1564    Tcl_Write(handle, (char *) &c, 1);
1565
1566    resolution = 0;
1567    while (statePtr->num >> resolution) {
1568	resolution++;
1569    }
1570    c = 111 + resolution * 17;
1571    Tcl_Write(handle, (char *) &c, 1);
1572
1573    statePtr->num = 1 << resolution;
1574
1575    /*
1576     * Background color
1577     */
1578
1579    c = 0;
1580    Tcl_Write(handle, (char *) &c, 1);
1581
1582    /*
1583     * Zero for future expansion.
1584     */
1585
1586    Tcl_Write(handle, (char *) &c, 1);
1587
1588    for (x=0 ; x<statePtr->num ; x++) {
1589	c = statePtr->mapa[x][CM_RED];
1590	Tcl_Write(handle, (char *) &c, 1);
1591	c = statePtr->mapa[x][CM_GREEN];
1592	Tcl_Write(handle, (char *) &c, 1);
1593	c = statePtr->mapa[x][CM_BLUE];
1594	Tcl_Write(handle, (char *) &c, 1);
1595    }
1596
1597    /*
1598     * Write out extension for transparent colour index, if necessary.
1599     */
1600
1601    if (statePtr->alphaOffset) {
1602	c = GIF_EXTENSION;
1603	Tcl_Write(handle, (char *) &c, 1);
1604	Tcl_Write(handle, "\371\4\1\0\0\0", 7);
1605    }
1606
1607    c = GIF_START;
1608    Tcl_Write(handle, (char *) &c, 1);
1609    c = LSB(top);
1610    Tcl_Write(handle, (char *) &c, 1);
1611    c = MSB(top);
1612    Tcl_Write(handle, (char *) &c, 1);
1613    c = LSB(left);
1614    Tcl_Write(handle, (char *) &c, 1);
1615    c = MSB(left);
1616    Tcl_Write(handle, (char *) &c, 1);
1617
1618    c = LSB(width);
1619    Tcl_Write(handle, (char *) &c, 1);
1620    c = MSB(width);
1621    Tcl_Write(handle, (char *) &c, 1);
1622
1623    c = LSB(height);
1624    Tcl_Write(handle, (char *) &c, 1);
1625    c = MSB(height);
1626    Tcl_Write(handle, (char *) &c, 1);
1627
1628    c = 0;
1629    Tcl_Write(handle, (char *) &c, 1);
1630    c = resolution;
1631    Tcl_Write(handle, (char *) &c, 1);
1632
1633    statePtr->ssize = statePtr->rsize = blockPtr->width;
1634    statePtr->csize = blockPtr->height;
1635    compress(resolution+1, handle, ReadValue, (ClientData) statePtr);
1636
1637    c = 0;
1638    Tcl_Write(handle, (char *) &c, 1);
1639    c = GIF_TERMINATOR;
1640    Tcl_Write(handle, (char *) &c, 1);
1641
1642    return TCL_OK;
1643}
1644
1645static int
1646color(
1647    GifWriterState *statePtr,
1648    int red, int green, int blue,
1649    unsigned char mapa[MAXCOLORMAPSIZE][3])
1650{
1651    int x = (statePtr->alphaOffset != 0);
1652
1653    for (; x<=MAXCOLORMAPSIZE ; x++) {
1654	if ((mapa[x][CM_RED] == red) && (mapa[x][CM_GREEN] == green) &&
1655		(mapa[x][CM_BLUE] == blue)) {
1656	    return x;
1657	}
1658    }
1659    return -1;
1660}
1661
1662static int
1663nuevo(
1664    GifWriterState *statePtr,
1665    int red, int green, int blue,
1666    unsigned char mapa[MAXCOLORMAPSIZE][3])
1667{
1668    int x = (statePtr->alphaOffset != 0);
1669
1670    for (; x<=statePtr->num ; x++) {
1671	if ((mapa[x][CM_RED] == red) && (mapa[x][CM_GREEN] == green) &&
1672		(mapa[x][CM_BLUE] == blue)) {
1673	    return 0;
1674	}
1675    }
1676    return 1;
1677}
1678
1679static void
1680savemap(
1681    GifWriterState *statePtr,
1682    Tk_PhotoImageBlock *blockPtr,
1683    unsigned char mapa[MAXCOLORMAPSIZE][3])
1684{
1685    unsigned char *colores;
1686    int x, y;
1687    unsigned char red, green, blue;
1688
1689    if (statePtr->alphaOffset) {
1690	statePtr->num = 0;
1691	mapa[0][CM_RED] = 0xd9;
1692	mapa[0][CM_GREEN] = 0xd9;
1693	mapa[0][CM_BLUE] = 0xd9;
1694    } else {
1695	statePtr->num = -1;
1696    }
1697
1698    for (y=0 ; y<blockPtr->height ; y++) {
1699	colores = blockPtr->pixelPtr + blockPtr->offset[0] + y*blockPtr->pitch;
1700	for (x=0 ; x<blockPtr->width ; x++) {
1701	    if (!statePtr->alphaOffset || colores[statePtr->alphaOffset]!=0) {
1702		red = colores[0];
1703		green = colores[statePtr->greenOffset];
1704		blue = colores[statePtr->blueOffset];
1705		if (nuevo(statePtr, red, green, blue, mapa)) {
1706		    statePtr->num++;
1707		    if (statePtr->num >= MAXCOLORMAPSIZE) {
1708			return;
1709		    }
1710		    mapa[statePtr->num][CM_RED] = red;
1711		    mapa[statePtr->num][CM_GREEN] = green;
1712		    mapa[statePtr->num][CM_BLUE] = blue;
1713		}
1714	    }
1715	    colores += statePtr->pixelSize;
1716	}
1717    }
1718}
1719
1720static int
1721ReadValue(
1722    ClientData clientData)
1723{
1724    GifWriterState *statePtr = (GifWriterState *) clientData;
1725    unsigned int col;
1726
1727    if (statePtr->csize == 0) {
1728	return EOF;
1729    }
1730    if (statePtr->alphaOffset && statePtr->pixelo[statePtr->alphaOffset]==0) {
1731	col = 0;
1732    } else {
1733	col = color(statePtr, statePtr->pixelo[0],
1734		statePtr->pixelo[statePtr->greenOffset],
1735		statePtr->pixelo[statePtr->blueOffset], statePtr->mapa);
1736    }
1737    statePtr->pixelo += statePtr->pixelSize;
1738    if (--statePtr->ssize <= 0) {
1739	statePtr->ssize = statePtr->rsize;
1740	statePtr->csize--;
1741	statePtr->pixelo += statePtr->pixelPitch
1742		- (statePtr->rsize * statePtr->pixelSize);
1743    }
1744
1745    return col;
1746}
1747
1748/*
1749 *-----------------------------------------------------------------------
1750 *
1751 * miGIF Compression - mouse and ivo's GIF-compatible compression
1752 *
1753 *		-run length encoding compression routines-
1754 *
1755 * Copyright (C) 1998 Hutchison Avenue Software Corporation
1756 *		 http://www.hasc.com
1757 *		 info@hasc.com
1758 *
1759 * Permission to use, copy, modify, and distribute this software and its
1760 * documentation for any purpose and without fee is hereby granted, provided
1761 * that the above copyright notice appear in all copies and that both that
1762 * copyright notice and this permission notice appear in supporting
1763 * documentation. This software is provided "AS IS." The Hutchison Avenue
1764 * Software Corporation disclaims all warranties, either express or implied,
1765 * including but not limited to implied warranties of merchantability and
1766 * fitness for a particular purpose, with respect to this code and
1767 * accompanying documentation.
1768 *
1769 * The miGIF compression routines do not, strictly speaking, generate files
1770 * conforming to the GIF spec, since the image data is not LZW-compressed
1771 * (this is the point: in order to avoid transgression of the Unisys patent on
1772 * the LZW algorithm.) However, miGIF generates data streams that any
1773 * reasonably sane LZW decompresser will decompress to what we want.
1774 *
1775 * miGIF compression uses run length encoding. It compresses horizontal runs
1776 * of pixels of the same color. This type of compression gives good results on
1777 * images with many runs, for example images with lines, text and solid shapes
1778 * on a solid-colored background. It gives little or no compression on images
1779 * with few runs, for example digital or scanned photos.
1780 *
1781 *				 der Mouse
1782 *			mouse@rodents.montreal.qc.ca
1783 *	      7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B
1784 *
1785 *			       ivo@hasc.com
1786 *
1787 * The Graphics Interchange Format(c) is the Copyright property of CompuServe
1788 * Incorporated. GIF(sm) is a Service Mark property of CompuServe Incorporated.
1789 *
1790 *-----------------------------------------------------------------------
1791 */
1792
1793typedef struct {
1794    int runlengthPixel;
1795    int runlengthBaseCode;
1796    int runlengthCount;
1797    int runlengthTablePixel;
1798    int runlengthTableMax;
1799    int justCleared;
1800    int outputBits;
1801    int outputBitsInit;
1802    int outputCount;
1803    int outputBump;
1804    int outputBumpInit;
1805    int outputClear;
1806    int outputClearInit;
1807    int maxOcodes;
1808    int codeClear;
1809    int codeEOF;
1810    unsigned int obuf;
1811    int obits;
1812    Tcl_Channel ofile;
1813    unsigned char oblock[256];
1814    int oblen;
1815} miGIFState_t;
1816
1817/*
1818 * Used only when debugging GIF compression code
1819 */
1820/* #define MIGIF_DEBUGGING_ENVARS */
1821
1822#ifdef MIGIF_DEBUGGING_ENVARS
1823
1824/*
1825 * This debugging code is _absolutely_ not thread-safe. It's also not normally
1826 * enabled either.
1827 */
1828
1829static int verboseSet = 0;
1830static int verbose;
1831#define MIGIF_VERBOSE		(verboseSet?verbose:setVerbose())
1832#define DEBUGMSG(printfArgs)	if (MIGIF_VERBOSE) { printf printfArgs; }
1833
1834static int
1835setVerbose(void)
1836{
1837    verbose = !!getenv("MIGIF_VERBOSE");
1838    verboseSet = 1;
1839    return verbose;
1840}
1841
1842static const char *
1843binformat(
1844    unsigned int v,
1845    int nbits)
1846{
1847    static char bufs[8][64];
1848    static int bhand = 0;
1849    unsigned int bit;
1850    int bno;
1851    char *bp;
1852
1853    bhand--;
1854    if (bhand < 0) {
1855	bhand = (sizeof(bufs) / sizeof(bufs[0])) - 1;
1856    }
1857    bp = &bufs[bhand][0];
1858    for (bno=nbits-1,bit=((unsigned int)1)<<bno ; bno>=0 ; bno--,bit>>=1) {
1859	*bp++ = (v & bit) ? '1' : '0';
1860	if (((bno&3) == 0) && (bno != 0)) {
1861	    *bp++ = '.';
1862	}
1863    }
1864    *bp = '\0';
1865    return &bufs[bhand][0];
1866}
1867#else /* !MIGIF_DEBUGGING_ENVARS */
1868#define DEBUGMSG(printfArgs) /* do nothing */
1869#endif
1870
1871static void
1872writeBlock(
1873    miGIFState_t *statePtr)
1874{
1875    unsigned char c;
1876
1877#ifdef MIGIF_DEBUGGING_ENVARS
1878    if (MIGIF_VERBOSE) {
1879	int i;
1880	printf("writeBlock %d:", statePtr->oblen);
1881	for (i=0 ; i<statePtr->oblen ; i++) {
1882	    printf(" %02x", statePtr->oblock[i]);
1883	}
1884	printf("\n");
1885    }
1886#endif
1887    c = statePtr->oblen;
1888    Tcl_Write(statePtr->ofile, (char *) &c, 1);
1889    Tcl_Write(statePtr->ofile, (char *) &statePtr->oblock[0], statePtr->oblen);
1890    statePtr->oblen = 0;
1891}
1892
1893static void
1894blockOut(
1895    miGIFState_t *statePtr,
1896    unsigned c)
1897{
1898    DEBUGMSG(("blockOut %s\n", binformat(c, 8)));
1899    statePtr->oblock[statePtr->oblen++] = (unsigned char) c;
1900    if (statePtr->oblen >= 255) {
1901	writeBlock(statePtr);
1902    }
1903}
1904
1905static void
1906blockFlush(
1907    miGIFState_t *statePtr)
1908{
1909    DEBUGMSG(("blockFlush\n"));
1910    if (statePtr->oblen > 0) {
1911	writeBlock(statePtr);
1912    }
1913}
1914
1915static void
1916output(
1917    miGIFState_t *statePtr,
1918    int val)
1919{
1920    DEBUGMSG(("output %s [%s %d %d]\n", binformat(val, statePtr->outputBits),
1921	    binformat(statePtr->obuf, statePtr->obits), statePtr->obits,
1922	    statePtr->outputBits));
1923    statePtr->obuf |= val << statePtr->obits;
1924    statePtr->obits += statePtr->outputBits;
1925    while (statePtr->obits >= 8) {
1926	blockOut(statePtr, statePtr->obuf & 0xff);
1927	statePtr->obuf >>= 8;
1928	statePtr->obits -= 8;
1929    }
1930    DEBUGMSG(("output leaving [%s %d]\n",
1931	    binformat(statePtr->obuf, statePtr->obits), statePtr->obits));
1932}
1933
1934static void
1935outputFlush(
1936    miGIFState_t *statePtr)
1937{
1938    DEBUGMSG(("outputFlush\n"));
1939    if (statePtr->obits > 0) {
1940	blockOut(statePtr, statePtr->obuf);
1941    }
1942    blockFlush(statePtr);
1943}
1944
1945static void
1946didClear(
1947    miGIFState_t *statePtr)
1948{
1949    DEBUGMSG(("didClear\n"));
1950    statePtr->outputBits = statePtr->outputBitsInit;
1951    statePtr->outputBump = statePtr->outputBumpInit;
1952    statePtr->outputClear = statePtr->outputClearInit;
1953    statePtr->outputCount = 0;
1954    statePtr->runlengthTableMax = 0;
1955    statePtr->justCleared = 1;
1956}
1957
1958static void
1959outputPlain(
1960    miGIFState_t *statePtr,
1961    int c)
1962{
1963    DEBUGMSG(("outputPlain %s\n", binformat(c, statePtr->outputBits)));
1964    statePtr->justCleared = 0;
1965    output(statePtr, c);
1966    statePtr->outputCount++;
1967    if (statePtr->outputCount >= statePtr->outputBump) {
1968	statePtr->outputBits++;
1969	statePtr->outputBump += 1 << (statePtr->outputBits - 1);
1970    }
1971    if (statePtr->outputCount >= statePtr->outputClear) {
1972	output(statePtr, statePtr->codeClear);
1973	didClear(statePtr);
1974    }
1975}
1976
1977static unsigned int
1978isqrt(
1979    unsigned int x)
1980{
1981    unsigned int r;
1982    unsigned int v;
1983
1984    if (x < 2) {
1985	return x;
1986    }
1987    for (v=x,r=1 ; v ; v>>=2,r<<=1);
1988    while (1) {
1989	v = ((x / r) + r) / 2;
1990	if (v==r || v==r+1) {
1991	    return r;
1992	}
1993	r = v;
1994    }
1995}
1996
1997static int
1998computeTriangleCount(
1999    unsigned int count,
2000    unsigned int nrepcodes)
2001{
2002    unsigned int perrep;
2003    unsigned int cost;
2004
2005    cost = 0;
2006    perrep = (nrepcodes * (nrepcodes+1)) / 2;
2007    while (count >= perrep) {
2008	cost += nrepcodes;
2009	count -= perrep;
2010    }
2011    if (count > 0) {
2012	unsigned int n = isqrt(count);
2013
2014	while (n*(n+1) >= 2*count) {
2015	    n--;
2016	}
2017	while (n*(n+1) < 2*count) {
2018	    n++;
2019	}
2020	cost += n;
2021    }
2022    return (int) cost + 1;
2023}
2024
2025static void
2026maxOutputClear(
2027    miGIFState_t *statePtr)
2028{
2029    statePtr->outputClear = statePtr->maxOcodes;
2030}
2031
2032static void
2033resetOutputClear(
2034    miGIFState_t *statePtr)
2035{
2036    statePtr->outputClear = statePtr->outputClearInit;
2037    if (statePtr->outputCount >= statePtr->outputClear) {
2038	output(statePtr, statePtr->codeClear);
2039	didClear(statePtr);
2040    }
2041}
2042
2043static void
2044runlengthFlushFromClear(
2045    miGIFState_t *statePtr,
2046    int count)
2047{
2048    int n;
2049
2050    DEBUGMSG(("runlengthFlushFromClear %d\n", count));
2051    maxOutputClear(statePtr);
2052    statePtr->runlengthTablePixel = statePtr->runlengthPixel;
2053    n = 1;
2054    while (count > 0) {
2055	if (n == 1) {
2056	    statePtr->runlengthTableMax = 1;
2057	    outputPlain(statePtr, statePtr->runlengthPixel);
2058	    count--;
2059	} else if (count >= n) {
2060	    statePtr->runlengthTableMax = n;
2061	    outputPlain(statePtr, statePtr->runlengthBaseCode+n-2);
2062	    count -= n;
2063	} else if (count == 1) {
2064	    statePtr->runlengthTableMax++;
2065	    outputPlain(statePtr, statePtr->runlengthPixel);
2066	    count = 0;
2067	} else {
2068	    statePtr->runlengthTableMax++;
2069	    outputPlain(statePtr, statePtr->runlengthBaseCode+count-2);
2070	    count = 0;
2071	}
2072	if (statePtr->outputCount == 0) {
2073	    n = 1;
2074	} else {
2075	    n++;
2076	}
2077    }
2078    resetOutputClear(statePtr);
2079    DEBUGMSG(("runlengthFlushFromClear leaving tableMax=%d\n",
2080	    statePtr->runlengthTableMax));
2081}
2082
2083static void
2084runlengthFlushClearOrRep(
2085    miGIFState_t *statePtr,
2086    int count)
2087{
2088    int withclr;
2089
2090    DEBUGMSG(("runlengthFlushClearOrRep %d\n", count));
2091    withclr = computeTriangleCount((unsigned) count,
2092	    (unsigned) statePtr->maxOcodes);
2093    if (withclr < count) {
2094	output(statePtr, statePtr->codeClear);
2095	didClear(statePtr);
2096	runlengthFlushFromClear(statePtr, count);
2097    } else {
2098	for (; count>0 ; count--) {
2099	    outputPlain(statePtr, statePtr->runlengthPixel);
2100	}
2101    }
2102}
2103
2104static void
2105runlengthFlushWithTable(
2106    miGIFState_t *statePtr,
2107    int count)
2108{
2109    int repmax;
2110    int repleft;
2111    int leftover;
2112
2113    DEBUGMSG(("runlengthFlushWithTable %d\n", count));
2114    repmax = count / statePtr->runlengthTableMax;
2115    leftover = count % statePtr->runlengthTableMax;
2116    repleft = (leftover ? 1 : 0);
2117    if (statePtr->outputCount+repmax+repleft > statePtr->maxOcodes) {
2118	repmax = statePtr->maxOcodes - statePtr->outputCount;
2119	leftover = count - (repmax * statePtr->runlengthTableMax);
2120	repleft = computeTriangleCount((unsigned) leftover,
2121		(unsigned) statePtr->maxOcodes);
2122    }
2123    DEBUGMSG(("runlengthFlushWithTable repmax=%d leftover=%d repleft=%d\n",
2124	    repmax, leftover, repleft));
2125    if (computeTriangleCount((unsigned) count, (unsigned) statePtr->maxOcodes)
2126	    < repmax+repleft) {
2127	output(statePtr, statePtr->codeClear);
2128	didClear(statePtr);
2129	runlengthFlushFromClear(statePtr, count);
2130	return;
2131    }
2132    maxOutputClear(statePtr);
2133    for (; repmax>0 ; repmax--) {
2134	outputPlain(statePtr,
2135		statePtr->runlengthBaseCode + statePtr->runlengthTableMax - 2);
2136    }
2137    if (leftover) {
2138	if (statePtr->justCleared) {
2139	    runlengthFlushFromClear(statePtr, leftover);
2140	} else if (leftover == 1) {
2141	    outputPlain(statePtr, statePtr->runlengthPixel);
2142	} else {
2143	    outputPlain(statePtr, statePtr->runlengthBaseCode + leftover - 2);
2144	}
2145    }
2146    resetOutputClear(statePtr);
2147}
2148
2149static void
2150runlengthFlush(
2151    miGIFState_t *statePtr)
2152{
2153    DEBUGMSG(("runlengthFlush [ %d %d\n", statePtr->runlengthCount,
2154	    statePtr->runlengthPixel));
2155    if (statePtr->runlengthCount == 1) {
2156	outputPlain(statePtr, statePtr->runlengthPixel);
2157	statePtr->runlengthCount = 0;
2158	DEBUGMSG(("runlengthFlush ]\n"));
2159	return;
2160    }
2161    if (statePtr->justCleared) {
2162	runlengthFlushFromClear(statePtr, statePtr->runlengthCount);
2163    } else if ((statePtr->runlengthTableMax < 2)
2164	    || (statePtr->runlengthTablePixel != statePtr->runlengthPixel)) {
2165	runlengthFlushClearOrRep(statePtr, statePtr->runlengthCount);
2166    } else {
2167	runlengthFlushWithTable(statePtr, statePtr->runlengthCount);
2168    }
2169    DEBUGMSG(("runlengthFlush ]\n"));
2170    statePtr->runlengthCount = 0;
2171}
2172
2173static void
2174compress(
2175    int initBits,
2176    Tcl_Channel handle,
2177    ifunptr readValue,
2178    ClientData clientData)
2179{
2180    int c;
2181    miGIFState_t state, *statePtr = &state;
2182
2183    memset(statePtr, 0, sizeof(state));
2184
2185    statePtr->ofile = handle;
2186    statePtr->obuf = 0;
2187    statePtr->obits = 0;
2188    statePtr->oblen = 0;
2189    statePtr->codeClear = 1 << (initBits - 1);
2190    statePtr->codeEOF = statePtr->codeClear + 1;
2191    statePtr->runlengthBaseCode = statePtr->codeEOF + 1;
2192    statePtr->outputBumpInit = (1 << (initBits - 1)) - 1;
2193
2194    /*
2195     * For images with a lot of runs, making outputClearInit larger will give
2196     * better compression.
2197     */
2198
2199    statePtr->outputClearInit =
2200	    (initBits <= 3) ? 9 : (statePtr->outputBumpInit-1);
2201#ifdef MIGIF_DEBUGGING_ENVARS
2202    {
2203	const char *ocienv = getenv("MIGIF_OUT_CLEAR_INIT");
2204
2205	if (ocienv) {
2206	    statePtr->outputClearInit = atoi(ocienv);
2207	    DEBUGMSG(("[overriding outputClearInit to %d]\n",
2208		    statePtr->outputClearInit));
2209	}
2210    }
2211#endif
2212    statePtr->outputBitsInit = initBits;
2213    statePtr->maxOcodes =
2214	    (1 << GIFBITS) - ((1 << (statePtr->outputBitsInit - 1)) + 3);
2215    didClear(statePtr);
2216    output(statePtr, statePtr->codeClear);
2217    statePtr->runlengthCount = 0;
2218    while (1) {
2219	c = readValue(clientData);
2220	if (statePtr->runlengthCount>0 && statePtr->runlengthPixel!=c) {
2221	    runlengthFlush(statePtr);
2222	}
2223	if (c == EOF) {
2224	    break;
2225	}
2226	if (statePtr->runlengthPixel == c) {
2227	    statePtr->runlengthCount++;
2228	} else {
2229	    statePtr->runlengthPixel = c;
2230	    statePtr->runlengthCount = 1;
2231	}
2232    }
2233    output(statePtr, statePtr->codeEOF);
2234    outputFlush(statePtr);
2235}
2236
2237/*
2238 *-----------------------------------------------------------------------
2239 *
2240 * End of miGIF section - See copyright notice at start of section.
2241 *
2242 *-----------------------------------------------------------------------
2243 */
2244
2245/*
2246 * Local Variables:
2247 * mode: c
2248 * c-basic-offset: 4
2249 * fill-column: 78
2250 * End:
2251 */
2252