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

Diff of /projs/dtats/trunk/shared_source/c_tk_base_7_5_w_mods/tkimggif.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.69  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25