/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkimggif.c
ViewVC logotype

Annotation of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkimggif.c

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25