tkImgGIF.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:53k
源码类别:

通讯编程

开发平台:

Visual C++

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