summaryrefslogtreecommitdiffstats
path: root/tkimg/gif/gif.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2017-01-03 21:51:01 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2017-01-03 21:51:01 (GMT)
commita780057cc1b51dd3a557549c3cf2431f09136c0d (patch)
tree717f78052c55596449b27743171d7e170c4d39a0 /tkimg/gif/gif.c
parent7749430b9352c1eaf5dca7d8a89a6d35f565ef24 (diff)
downloadblt-a780057cc1b51dd3a557549c3cf2431f09136c0d.zip
blt-a780057cc1b51dd3a557549c3cf2431f09136c0d.tar.gz
blt-a780057cc1b51dd3a557549c3cf2431f09136c0d.tar.bz2
upgrade tkimg to 1.4.6
Diffstat (limited to 'tkimg/gif/gif.c')
-rw-r--r--tkimg/gif/gif.c1760
1 files changed, 0 insertions, 1760 deletions
diff --git a/tkimg/gif/gif.c b/tkimg/gif/gif.c
deleted file mode 100644
index 522e044..0000000
--- a/tkimg/gif/gif.c
+++ /dev/null
@@ -1,1760 +0,0 @@
-/*
- * gif.c --
- *
- * GIF photo image type, Tcl/Tk package
- *
- * A photo image file handler for GIF files. Reads 87a and 89a GIF
- * files. At present, there only is a file write function. GIF images may be
- * read using the -data option of the photo image. The data may be
- * given as a binary string in a Tcl_Obj or by representing
- * the data as BASE64 encoded ascii. Derived from the giftoppm code
- * found in the pbmplus package and tkImgFmtPPM.c in the tk4.0b2
- * distribution.
- *
- * Copyright (c) 2002 Andreas Kupries <andreas_kupries@users.sourceforge.net>
- * Copyright (c) 1997-2003 Jan Nijtmans <nijtmans@users.sourceforge.net>
- *
- * Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee
- * Copyright (c) 1995-1997 Sun Microsystems, Inc.
- * Copyright (c) 1997 Australian National University
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * This file also contains code from the giftoppm program, which is
- * copyrighted as follows:
- *
- * +-------------------------------------------------------------------+
- * | Copyright 1990, David Koblas. |
- * | Permission to use, copy, modify, and distribute this software |
- * | and its documentation for any purpose and without fee is hereby |
- * | granted, provided that the above copyright notice appear in all |
- * | copies and that both that copyright notice and this permission |
- * | notice appear in supporting documentation. This software is |
- * | provided "as is" without express or implied warranty. |
- * +-------------------------------------------------------------------+
- *
- * $Id: gif.c,v 1.1.1.1 2016/01/25 21:20:46 joye Exp $
- *
- */
-
-/*
- * Generic initialization code, parameterized via CPACKAGE and PACKAGE.
- */
-
-#include "init.c"
-
-/*
- * Non-ASCII encoding support:
- * Most data in a GIF image is binary and is treated as such. However,
- * a few key bits are stashed in ASCII. If we try to compare those pieces
- * to the char they represent, it will fail on any non-ASCII (eg, EBCDIC)
- * system. To accomodate these systems, we test against the numeric value
- * of the ASCII characters instead of the characters themselves. This is
- * encoding independant.
- */
-
-# define GIF87a "\x47\x49\x46\x38\x37\x61" /* ASCII GIF87a */
-# define GIF89a "\x47\x49\x46\x38\x39\x61" /* ASCII GIF89a */
-# define GIF_TERMINATOR 0x3b /* ASCII ; */
-# define GIF_EXTENSION 0x21 /* ASCII ! */
-# define GIF_START 0x2c /* ASCII , */
-
-typedef struct {
- unsigned char buf[280];
- int bytes;
- int done;
- unsigned int window;
- int bitsInWindow;
- unsigned char *c;
- tkimg_MFile handle;
-} GIFImageConfig;
-
-/*
- * The format record for the GIF file format:
- */
-
-static int CommonRead(Tcl_Interp *interp,
- GIFImageConfig *gifConfPtr, const char *fileName, Tcl_Obj *format,
- Tk_PhotoHandle imageHandle, int destX, int destY,
- int width, int height, int srcX, int srcY);
-
-static int CommonWrite(Tcl_Interp *interp,
- tkimg_MFile *handle, Tcl_Obj *format,
- Tk_PhotoImageBlock *blockPtr);
-
-#define INTERLACE 0x40
-#define LOCALCOLORMAP 0x80
-#define BitSet(byte, bit) (((byte) & (bit)) == (bit))
-#define MAXCOLORMAPSIZE 256
-#define CM_RED 0
-#define CM_GREEN 1
-#define CM_BLUE 2
-#define CM_ALPHA 3
-#define MAX_LWZ_BITS 12
-#define LM_to_uint(a,b) (((b)<<8)|(a))
-#define ReadOK(handle,buf,len) (tkimg_Read(handle, (char *)(buf), len) == len)
-
-/*
- * Prototypes for local procedures defined in this file:
- */
-
-static int DoExtension(GIFImageConfig *gifConfPtr, int label,
- int *transparent);
-
-static int GetCode(GIFImageConfig *gifConfPtr, int code_size,
- int flag);
-
-static int GetDataBlock(GIFImageConfig *gifConfPtr,
- unsigned char *buf);
-
-static int ReadColorMap(GIFImageConfig *gifConfPtr, int number,
- unsigned char buffer[MAXCOLORMAPSIZE][4]);
-
-static int ReadGIFHeader(GIFImageConfig *gifConfPtr,
- int *widthPtr, int *heightPtr);
-
-static int ReadImage(Tcl_Interp *interp,
- char *imagePtr, GIFImageConfig *gifConfPtr, int len, int rows,
- unsigned char cmap[MAXCOLORMAPSIZE][4],
- int width, int height, int srcX, int srcY,
- int interlace, int transparent);
-
-/*
- *----------------------------------------------------------------------
- *
- * ChnMatch --
- *
- * This procedure is invoked by the photo image type to see if
- * a channel contains image data in GIF format.
- *
- * Results:
- * The return value is 1 if the first characters in channel chan
- * look like GIF data, and 0 otherwise.
- *
- * Side effects:
- * The access position in f may change.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ChnMatch(
- Tcl_Channel chan, /* The image channel, open for reading. */
- const char *fileName, /* The name of the image file. */
- Tcl_Obj *format, /* User-specified format object, or NULL. */
- int *widthPtr, /* The dimensions of the image are */
- int *heightPtr, /* returned here if the file is a valid
- * raw GIF file. */
- Tcl_Interp *interp /* interpreter */
-) {
- GIFImageConfig gifConf;
-
- memset(&gifConf, 0, sizeof(GIFImageConfig));
-
- gifConf.handle.data = (char *) chan;
- gifConf.handle.state = IMG_CHAN;
-
- return ReadGIFHeader(&gifConf, widthPtr, heightPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ChnRead --
- *
- * This procedure is called by the photo image type to read
- * GIF format data from a channel and write it into a given
- * photo image.
- *
- * Results:
- * A standard TCL completion code. If TCL_ERROR is returned
- * then an error message is left in the interp's result.
- *
- * Side effects:
- * The access position in channel chan is changed, and new data is
- * added to the image given by imageHandle.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ChnRead(interp, chan, fileName, format, imageHandle, destX, destY,
- width, height, srcX, srcY)
- Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
- Tcl_Channel chan; /* The image channel, open for reading. */
- const char *fileName; /* The name of the image file. */
- Tcl_Obj *format; /* User-specified format object, or NULL. */
- Tk_PhotoHandle imageHandle; /* The photo image to write into. */
- int destX, destY; /* Coordinates of top-left pixel in
- * photo image to be written to. */
- int width, height; /* Dimensions of block of photo image to
- * be written to. */
- int srcX, srcY; /* Coordinates of top-left pixel to be used
- * in image being read. */
-{
- GIFImageConfig gifConf;
-
- memset(&gifConf, 0, sizeof(GIFImageConfig));
-
- gifConf.handle.data = (char *) chan;
- gifConf.handle.state = IMG_CHAN;
-
- return CommonRead(interp, &gifConf, fileName, format,
- imageHandle, destX, destY, width, height, srcX, srcY);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CommonRead --
- *
- * This procedure is called by the photo image type to read
- * GIF format data from a file and write it into a given
- * photo image.
- *
- * Results:
- * A standard TCL completion code. If TCL_ERROR is returned
- * then an error message is left in the interp's result.
- *
- * Side effects:
- * The access position in file f is changed, and new data is
- * added to the image given by imageHandle.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-CommonRead(interp, gifConfPtr, fileName, format, imageHandle, destX, destY,
- width, height, srcX, srcY)
- Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
- GIFImageConfig *gifConfPtr; /* The image file, open for reading. */
- const char *fileName; /* The name of the image file. */
- Tcl_Obj *format; /* User-specified format object, or NULL. */
- Tk_PhotoHandle imageHandle; /* The photo image to write into. */
- int destX, destY; /* Coordinates of top-left pixel in
- * photo image to be written to. */
- int width, height; /* Dimensions of block of photo image to
- * be written to. */
- int srcX, srcY; /* Coordinates of top-left pixel to be used
- * in image being read. */
-{
- int fileWidth, fileHeight, imageWidth, imageHeight;
- int nBytes, index = 0, objc = 0;
- Tcl_Obj **objv = NULL;
- Tk_PhotoImageBlock block;
- unsigned char buf[100];
- char *trashBuffer = NULL;
- unsigned char *pixBuf = NULL;
- int bitPixel;
- unsigned char colorMap[MAXCOLORMAPSIZE][4];
- int transparent = -1;
-
- if (tkimg_ListObjGetElements(interp, format, &objc, &objv) != TCL_OK) {
- return TCL_ERROR;
- }
- if (objc > 1) {
- char *c = Tcl_GetStringFromObj(objv[1], &nBytes);
- if ((objc > 3) || ((objc == 3) && ((c[0] != '-') ||
- (c[1] != 'i') || strncmp(c, "-index", strlen(c))))) {
- Tcl_AppendResult(interp, "invalid format: \"",
- tkimg_GetStringFromObj(format, NULL), "\"", (char *) NULL);
- return TCL_ERROR;
- }
- if (Tcl_GetIntFromObj(interp, objv[objc-1], &index) != TCL_OK) {
- return TCL_ERROR;
- }
- }
-
- if (!ReadGIFHeader(gifConfPtr, &fileWidth, &fileHeight)) {
- Tcl_AppendResult(interp, "couldn't read GIF header from file \"",
- fileName, "\"", NULL);
- return TCL_ERROR;
- }
- if ((fileWidth <= 0) || (fileHeight <= 0)) {
- Tcl_AppendResult(interp, "GIF image file \"", fileName,
- "\" has dimension(s) <= 0", (char *) NULL);
- return TCL_ERROR;
- }
-
- if (tkimg_Read(&gifConfPtr->handle, (char *)buf, 3) != 3) {
- return TCL_OK;
- }
-
- bitPixel = 2<<(buf[0]&0x07);
-
- if (BitSet(buf[0], LOCALCOLORMAP)) { /* Global Colormap */
- if (!ReadColorMap(gifConfPtr, bitPixel, colorMap)) {
- Tcl_AppendResult(interp, "error reading color map",
- (char *) NULL);
- return TCL_ERROR;
- }
- }
-
- if ((srcX + width) > fileWidth) {
- width = fileWidth - srcX;
- }
- if ((srcY + height) > fileHeight) {
- height = fileHeight - srcY;
- }
- if ((width <= 0) || (height <= 0)
- || (srcX >= fileWidth) || (srcY >= fileHeight)) {
- return TCL_OK;
- }
-
- if (tkimg_PhotoExpand(interp, imageHandle, destX + width, destY + height) == TCL_ERROR) {
- return TCL_ERROR;;
- }
-
- block.pixelSize = 4;
- block.offset[0] = 0;
- block.offset[1] = 1;
- block.offset[2] = 2;
- block.offset[3] = 3;
- block.pixelPtr = NULL;
-
- while (1) {
- if (tkimg_Read(&gifConfPtr->handle, (char *)buf, 1) != 1) {
- /*
- * Premature end of image. We should really notify
- * the user, but for now just show garbage.
- */
-
- break;
- }
-
- if (buf[0] == GIF_TERMINATOR) {
- /*
- * GIF terminator.
- */
-
- Tcl_AppendResult(interp,"no image data for this index",
- (char *) NULL);
- goto error;
- }
-
- if (buf[0] == GIF_EXTENSION) {
- /*
- * This is a GIF extension.
- */
-
- if (tkimg_Read(&gifConfPtr->handle, (char *)buf, 1) != 1) {
- Tcl_AppendResult(interp,
- "error reading extension function code in GIF image",
- (char *) NULL);
- goto error;
- }
- if (DoExtension(gifConfPtr, buf[0], &transparent) < 0) {
- Tcl_AppendResult(interp, "error reading extension in GIF image",
- (char *) NULL);
- goto error;
- }
- continue;
- }
-
- if (buf[0] != GIF_START) {
- /*
- * Not a valid start character; ignore it.
- */
- continue;
- }
-
- if (tkimg_Read(&gifConfPtr->handle, (char *)buf, 9) != 9) {
- Tcl_AppendResult(interp,
- "couldn't read left/top/width/height in GIF image",
- (char *) NULL);
- goto error;
- }
-
- imageWidth = LM_to_uint(buf[4],buf[5]);
- imageHeight = LM_to_uint(buf[6],buf[7]);
-
- bitPixel = 2<<(buf[8]&0x07);
-
- if (index--) {
- /* this is not the image we want to read: skip it. */
- if (BitSet(buf[8], LOCALCOLORMAP)) {
- if (!ReadColorMap(gifConfPtr, bitPixel, colorMap)) {
- Tcl_AppendResult(interp,
- "error reading color map", (char *) NULL);
- goto error;
- }
- }
-
- /* If we've not yet allocated a trash buffer, do so now */
- if (trashBuffer == NULL) {
- nBytes = fileWidth * fileHeight * 3;
- trashBuffer = (char *) ckalloc((unsigned int) nBytes);
- }
-
- /*
- * Slurp! Process the data for this image and stuff it in a
- * trash buffer.
- *
- * Yes, it might be more efficient here to *not* store the data
- * (we're just going to throw it away later). However, I elected
- * to implement it this way for good reasons. First, I wanted to
- * avoid duplicating the (fairly complex) LWZ decoder in ReadImage.
- * Fine, you say, why didn't you just modify it to allow the use of
- * a NULL specifier for the output buffer? I tried that, but it
- * negatively impacted the performance of what I think will be the
- * common case: reading the first image in the file. Rather than
- * marginally improve the speed of the less frequent case, I chose
- * to maintain high performance for the common case.
- */
- if (ReadImage(interp, trashBuffer, gifConfPtr, imageWidth,
- imageHeight, colorMap, 0, 0, 0, 0, 0, -1) != TCL_OK) {
- goto error;
- }
- continue;
- }
-
- /* If a trash buffer has been allocated, free it now */
- if (trashBuffer != NULL) {
- ckfree((char *)trashBuffer);
- trashBuffer = NULL;
- }
- if (BitSet(buf[8], LOCALCOLORMAP)) {
- if (!ReadColorMap(gifConfPtr, bitPixel, colorMap)) {
- Tcl_AppendResult(interp, "error reading color map",
- (char *) NULL);
- goto error;
- }
- }
-
- index = LM_to_uint(buf[0],buf[1]);
- srcX -= index;
- if (srcX<0) {
- destX -= srcX; width += srcX;
- srcX = 0;
- }
-
- if (width > imageWidth) {
- width = imageWidth;
- }
-
- index = LM_to_uint(buf[2],buf[3]);
- srcY -= index;
- if (index > srcY) {
- destY -= srcY; height += srcY;
- srcY = 0;
- }
- if (height > imageHeight) {
- height = imageHeight;
- }
-
- if ((width <= 0) || (height <= 0)) {
- block.pixelPtr = 0;
- goto noerror;
- }
-
- block.width = width;
- block.height = height;
- block.pixelSize = (transparent>=0)?4:3;
- block.pitch = block.pixelSize * imageWidth;
- nBytes = block.pitch * imageHeight;
- pixBuf = (unsigned char *) ckalloc((unsigned) nBytes);
- block.pixelPtr = pixBuf;
-
- if (ReadImage(interp, (char *) block.pixelPtr, gifConfPtr, imageWidth, imageHeight,
- colorMap, fileWidth, fileHeight, srcX, srcY,
- BitSet(buf[8], INTERLACE), transparent) != TCL_OK) {
- goto error;
- }
- break;
- }
-
- block.pixelPtr = pixBuf + srcY * block.pitch + srcX * block.pixelSize;
- if (tkimg_PhotoPutBlock(interp, imageHandle, &block, destX, destY, width, height,
- (transparent == -1)? TK_PHOTO_COMPOSITE_SET: TK_PHOTO_COMPOSITE_OVERLAY) == TCL_ERROR) {
- goto error;
- }
-
- noerror:
- if (pixBuf) {
- ckfree((char *) pixBuf);
- }
- return TCL_OK;
-
- error:
- if (pixBuf) {
- ckfree((char *) pixBuf);
- }
- return TCL_ERROR;
-
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ObjMatch --
- *
- * This procedure is invoked by the photo image type to see if
- * an object contains image data in GIF format.
- *
- * Results:
- * The return value is 1 if the first characters in the object are
- * like GIF data, and 0 otherwise.
- *
- * Side effects:
- * the size of the image is placed in widthPtr and heightPtr.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ObjMatch(
- Tcl_Obj *data, /* the object containing the image data */
- Tcl_Obj *format, /* the image format object */
- int *widthPtr, /* where to put the image width */
- int *heightPtr, /* where to put the image height */
- Tcl_Interp *interp /* interpreter */
-) {
- GIFImageConfig gifConf;
-
- memset(&gifConf, 0, sizeof(GIFImageConfig));
-
- if (!tkimg_ReadInit(data, 'G', &gifConf.handle)) {
- return 0;
- }
- return ReadGIFHeader(&gifConf, widthPtr, heightPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ObjRead --
- *
- * This procedure is called by the photo image type to read
- * GIF format data from a base64 encoded string, and give it to
- * the photo image.
- *
- * Results:
- * A standard TCL completion code. If TCL_ERROR is returned
- * then an error message is left in the interp's result.
- *
- * Side effects:
- * new data is added to the image given by imageHandle. This
- * procedure calls FileReadGif by redefining the operation of
- * fprintf temporarily.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ObjRead(interp, data, format, imageHandle,
- destX, destY, width, height, srcX, srcY)
- Tcl_Interp *interp; /* interpreter for reporting errors in */
- Tcl_Obj *data; /* object containing the image */
- Tcl_Obj *format; /* format object if any */
- Tk_PhotoHandle imageHandle; /* the image to write this data into */
- int destX, destY; /* The rectangular region of the */
- int width, height; /* image to copy */
- int srcX, srcY;
-{
- GIFImageConfig gifConf;
-
- memset(&gifConf, 0, sizeof(GIFImageConfig));
-
- tkimg_ReadInit(data, 'G', &gifConf.handle);
- return CommonRead(interp, &gifConf, "inline data", format,
- imageHandle, destX, destY, width, height, srcX, srcY);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ReadGIFHeader --
- *
- * This procedure reads the GIF header from the beginning of a
- * GIF file and returns the dimensions of the image.
- *
- * Results:
- * The return value is 1 if file "f" appears to start with
- * a valid GIF header, 0 otherwise. If the header is valid,
- * then *widthPtr and *heightPtr are modified to hold the
- * dimensions of the image.
- *
- * Side effects:
- * The access position in f advances.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ReadGIFHeader(gifConfPtr, widthPtr, heightPtr)
- GIFImageConfig *gifConfPtr; /* Image file to read the header from */
- int *widthPtr, *heightPtr; /* The dimensions of the image are
- * returned here. */
-{
- unsigned char buf[7];
-
- if ((tkimg_Read(&gifConfPtr->handle, (char *)buf, 6) != 6)
- || ((strncmp(GIF87a, (char *) buf, 6) != 0)
- && (strncmp(GIF89a, (char *) buf, 6) != 0))) {
- return 0;
- }
-
- if (tkimg_Read(&gifConfPtr->handle, (char *)buf, 4) != 4) {
- return 0;
- }
-
- *widthPtr = LM_to_uint(buf[0],buf[1]);
- *heightPtr = LM_to_uint(buf[2],buf[3]);
- return 1;
-}
-
-/*
- *-----------------------------------------------------------------
- * The code below is copied from the giftoppm program and modified
- * just slightly.
- *-----------------------------------------------------------------
- */
-
-static int
-ReadColorMap(gifConfPtr, number, buffer)
- GIFImageConfig *gifConfPtr;
- int number;
- unsigned char buffer[MAXCOLORMAPSIZE][4];
-{
- int i;
- unsigned char rgb[3];
-
- for (i = 0; i < number; ++i) {
- if (! ReadOK(&gifConfPtr->handle, rgb, sizeof(rgb))) {
- return 0;
- }
-
- if (buffer) {
- buffer[i][CM_RED] = rgb[0] ;
- buffer[i][CM_GREEN] = rgb[1] ;
- buffer[i][CM_BLUE] = rgb[2] ;
- buffer[i][CM_ALPHA] = 255 ;
- }
- }
- return 1;
-}
-
-static int
-DoExtension(gifConfPtr, label, transparent)
- GIFImageConfig *gifConfPtr;
- int label;
- int *transparent;
-{
- int count;
-
- switch (label) {
- case 0x01: /* Plain Text Extension */
- break;
-
- case 0xff: /* Application Extension */
- break;
-
- case 0xfe: /* Comment Extension */
- do {
- count = GetDataBlock(gifConfPtr, (unsigned char*) gifConfPtr->buf);
- } while (count > 0);
- return count;
-
- case 0xf9: /* Graphic Control Extension */
- count = GetDataBlock(gifConfPtr, (unsigned char*) gifConfPtr->buf);
- if (count < 0) {
- return 1;
- }
- if ((gifConfPtr->buf[0] & 0x1) != 0) {
- *transparent = gifConfPtr->buf[3];
- }
-
- do {
- count = GetDataBlock(gifConfPtr, (unsigned char*) gifConfPtr->buf);
- } while (count > 0);
- return count;
- }
-
- do {
- count = GetDataBlock(gifConfPtr, (unsigned char*) gifConfPtr->buf);
- } while (count > 0);
- return count;
-}
-
-static int
-GetDataBlock(gifConfPtr, buf)
- GIFImageConfig *gifConfPtr;
- unsigned char *buf;
-{
- unsigned char count;
-
- if (! ReadOK(&gifConfPtr->handle,&count,1)) {
- return -1;
- }
-
- if ((count != 0) && (! ReadOK(&gifConfPtr->handle, buf, count))) {
- return -1;
- }
-
- return count;
-}
-
-
-
-/*
- *----------------------------------------------------------------------
- *
- * ReadImage --
- *
- * Process a GIF image from a given source, with a given height,
- * width, transparency, etc.
- *
- * This code is based on the code found in the ImageMagick GIF decoder,
- * which is (c) 2000 ImageMagick Studio.
- *
- * Some thoughts on our implementation:
- * It sure would be nice if ReadImage didn't take 11 parameters! I think
- * that if we were smarter, we could avoid doing that.
- *
- * Possible further optimizations: we could pull the GetCode function
- * directly into ReadImage, which would improve our speed.
- *
- * Results:
- * Processes a GIF image and loads the pixel data into a memory array.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ReadImage(interp, imagePtr, gifConfPtr, len, rows, cmap,
- width, height, srcX, srcY, interlace, transparent)
- Tcl_Interp *interp;
- char *imagePtr;
- GIFImageConfig *gifConfPtr;
- int len, rows;
- unsigned char cmap[MAXCOLORMAPSIZE][4];
- int width, height;
- int srcX, srcY;
- int interlace;
- int transparent;
-{
- unsigned char initialCodeSize;
- int v;
- int xpos = 0, ypos = 0, pass = 0, i;
- register char *pixelPtr;
- const static int interlaceStep[] = { 8, 8, 4, 2 };
- const static int interlaceStart[] = { 0, 4, 2, 1 };
- unsigned short prefix[(1 << MAX_LWZ_BITS)];
- unsigned char append[(1 << MAX_LWZ_BITS)];
- unsigned char stack[(1 << MAX_LWZ_BITS)*2];
- register unsigned char *top;
- int codeSize, clearCode, inCode, endCode, oldCode, maxCode,
- code, firstCode;
-
- /*
- * Initialize the decoder
- */
- if (! ReadOK(&gifConfPtr->handle,&initialCodeSize,1)) {
- Tcl_AppendResult(interp, "error reading GIF image: ",
- Tcl_PosixError(interp), (char *) NULL);
- return TCL_ERROR;
- }
- if (initialCodeSize > MAX_LWZ_BITS) {
- Tcl_AppendResult(interp, "error reading GIF image: malformed image", (char *) NULL);
- return TCL_ERROR;
- }
- if (transparent!=-1) {
- cmap[transparent][CM_RED] = 0;
- cmap[transparent][CM_GREEN] = 0;
- cmap[transparent][CM_BLUE] = 0;
- cmap[transparent][CM_ALPHA] = 0;
- }
-
- pixelPtr = imagePtr;
-
- /* Initialize the decoder */
- /* Set values for "special" numbers:
- * clear code reset the decoder
- * end code stop decoding
- * code size size of the next code to retrieve
- * max code next available table position
- */
- clearCode = 1 << (int) initialCodeSize;
- endCode = clearCode + 1;
- codeSize = (int) initialCodeSize + 1;
- maxCode = clearCode + 2;
- oldCode = -1;
- firstCode = -1;
-
- memset((void *)prefix, 0, (1 << MAX_LWZ_BITS) * sizeof(short));
- memset((void *)append, 0, (1 << MAX_LWZ_BITS) * sizeof(char));
- for (i = 0; i < clearCode; i++) {
- append[i] = i;
- }
- top = stack;
-
- GetCode(gifConfPtr, 0, 1);
-
- /* Read until we finish the image */
- for (i = 0, ypos = 0; i < rows; i++) {
- for (xpos = 0; xpos < len; ) {
-
- if (top == stack) {
- /* Bummer -- our stack is empty. Now we have to work! */
- code = GetCode(gifConfPtr, codeSize, 0);
- if (code < 0) {
- return TCL_OK;
- }
-
- if (code > maxCode || code == endCode) {
- /*
- * If we're doing things right, we should never
- * receive a code that is greater than our current
- * maximum code. If we do, bail, because our decoder
- * does not yet have that code set up.
- *
- * If the code is the magic endCode value, quit.
- */
- return TCL_OK;
- }
-
- if (code == clearCode) {
- /* Reset the decoder */
- codeSize = initialCodeSize + 1;
- maxCode = clearCode + 2;
- oldCode = -1;
- continue;
- }
-
- if (oldCode == -1) {
- /*
- * Last pass reset the decoder, so the first code we
- * see must be a singleton. Seed the stack with it,
- * and set up the old/first code pointers for
- * insertion into the string table. We can't just
- * roll this into the clearCode test above, because
- * at that point we have not yet read the next code.
- */
- *top++=append[code];
- oldCode = code;
- firstCode = code;
- continue;
- }
-
- inCode = code;
-
- if (code == maxCode) {
- /*
- * maxCode is always one bigger than our highest assigned
- * code. If the code we see is equal to maxCode, then
- * we are about to add a new string to the table. ???
- */
- *top++ = firstCode;
- code = oldCode;
- }
-
- while (code > clearCode) {
- /*
- * Populate the stack by tracing the string in the
- * string table from its tail to its head
- */
- *top++ = append[code];
- code = prefix[code];
- }
- firstCode = append[code];
-
- /*
- * If there's no more room in our string table, quit.
- * Otherwise, add a new string to the table
- */
- if (maxCode >= (1 << MAX_LWZ_BITS)) {
- return TCL_OK;
- }
-
- /* Push the head of the string onto the stack */
- *top++ = firstCode;
-
- /* Add a new string to the string table */
- prefix[maxCode] = oldCode;
- append[maxCode] = firstCode;
- maxCode++;
-
- /* maxCode tells us the maximum code value we can accept.
- * If we see that we need more bits to represent it than
- * we are requesting from the unpacker, we need to increase
- * the number we ask for.
- */
- if ((maxCode >= (1 << codeSize))
- && (maxCode < (1<<MAX_LWZ_BITS))) {
- codeSize++;
- }
- oldCode = inCode;
- }
-
- /* Pop the next color index off the stack */
- v = *(--top);
- if (v < 0) {
- return TCL_OK;
- }
-
- /*
- * If pixelPtr is null, we're skipping this image (presumably
- * there are more in the file and we will be called to read
- * one of them later)
- */
- *pixelPtr++ = cmap[v][CM_RED];
- *pixelPtr++ = cmap[v][CM_GREEN];
- *pixelPtr++ = cmap[v][CM_BLUE];
- if (transparent >= 0) {
- *pixelPtr++ = cmap[v][CM_ALPHA];
- }
- xpos++;
-
- }
-
- /* If interlacing, the next ypos is not just +1 */
- if (interlace) {
- ypos += interlaceStep[pass];
- while (ypos >= rows) {
- pass++;
- if (pass > 3) {
- return TCL_OK;
- }
- ypos = interlaceStart[pass];
- }
- } else {
- ypos++;
- }
- pixelPtr = imagePtr + (ypos) * len * ((transparent>=0)?4:3);
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * GetCode --
- *
- * Extract the next compression code from the file. In GIF's, the
- * compression codes are between 3 and 12 bits long and are then
- * packed into 8 bit bytes, left to right, for example:
- * bbbaaaaa
- * dcccccbb
- * eeeedddd
- * ...
- * We use a byte buffer read from the file and a sliding window
- * to unpack the bytes. Thanks to ImageMagick for the sliding window
- * idea.
- * args: handle the handle to read from
- * code_size size of the code to extract
- * flag boolean indicating whether the extractor
- * should be reset or not
- *
- * Results:
- * code the next compression code
- *
- * Side effects:
- * May consume more input from chan.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-GetCode(gifConfPtr, code_size, flag)
- GIFImageConfig *gifConfPtr;
- int code_size;
- int flag;
-{
- int ret;
-
- if (flag) {
- /* Initialize the decoder */
- gifConfPtr->bitsInWindow = 0;
- gifConfPtr->bytes = 0;
- gifConfPtr->window = 0;
- gifConfPtr->done = 0;
- gifConfPtr->c = NULL;
- return 0;
- }
-
- while (gifConfPtr->bitsInWindow < code_size) {
- /* Not enough bits in our window to cover the request */
- if (gifConfPtr->done) {
- return -1;
- }
- if (gifConfPtr->bytes == 0) {
- /* Not enough bytes in our buffer to add to the window */
- gifConfPtr->bytes = GetDataBlock(gifConfPtr, gifConfPtr->buf);
- gifConfPtr->c = gifConfPtr->buf;
- if (gifConfPtr->bytes <= 0) {
- gifConfPtr->done = 1;
- break;
- }
- }
- /* Tack another byte onto the window, see if that's enough */
- gifConfPtr->window += (*gifConfPtr->c) << gifConfPtr->bitsInWindow;
- gifConfPtr->c++;
- gifConfPtr->bitsInWindow += 8;
- gifConfPtr->bytes--;
- }
-
-
- /* The next code will always be the last code_size bits of the window */
- ret = gifConfPtr->window & ((1 << code_size) - 1);
-
- /* Shift data in the window to put the next code at the end */
- gifConfPtr->window >>= code_size;
- gifConfPtr->bitsInWindow -= code_size;
- return ret;
-}
-
-/*
- * This software is copyrighted as noted below. It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is
- * preserved on all copies.
- *
- * There is no warranty or other guarantee of fitness for this software,
- * it is provided solely "as is". Bug reports or fixes may be sent
- * to the author, who may or may not act on them as he desires.
- *
- * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the
- * source is available for no extra charge.
- *
- * If you modify this software, you should include a notice giving the
- * name of the person performing the modification, the date of modification,
- * and the reason for such modification.
- */
-
-
-/*
- * ChnWrite - writes a image in GIF format.
- *-------------------------------------------------------------------------
- * Author: Lolo
- * Engeneering Projects Area
- * Department of Mining
- * University of Oviedo
- * e-mail zz11425958@zeus.etsimo.uniovi.es
- * lolo@pcsig22.etsimo.uniovi.es
- * Date: Fri September 20 1996
- *
- * Modified for transparency handling (gif89a) and miGIF compression
- * by Jan Nijtmans <nijtmans@users.sourceforge.net>
- *
- *----------------------------------------------------------------------
- * FileWriteGIF-
- *
- * This procedure is called by the photo image type to write
- * GIF format data from a photo image into a given file
- *
- * Results:
- * A standard TCL completion code. If TCL_ERROR is returned
- * then an error message is left in the interp's result.
- *
- *----------------------------------------------------------------------
- */
-
- /*
- * Types, defines and variables needed to write and compress a GIF.
- */
-
-#define LSB(a) ((unsigned char) (((short)(a)) & 0x00FF))
-#define MSB(a) ((unsigned char) (((short)(a)) >> 8))
-
-#define GIFBITS 12
-#define HSIZE 5003 /* 80% occupancy */
-
-typedef struct {
- int ssize;
- int csize;
- int rsize;
- unsigned char *pixelo;
- int pixelSize;
- int pixelPitch;
- int greenOffset;
- int blueOffset;
- int alphaOffset;
- int num;
- unsigned char mapa[MAXCOLORMAPSIZE][3];
-} GifWriterState;
-
-typedef int (* ifunptr) (GifWriterState *statePtr);
-
-/*
- * Definition of new functions to write GIFs
- */
-
-static int color(GifWriterState *statePtr, int red, int green, int blue);
-
-static void compress(GifWriterState *statePtr, int init_bits, tkimg_MFile *handle,
- ifunptr readValue);
-
-static int nuevo(GifWriterState *statePtr, int red, int green ,int blue);
-
-static int savemap(GifWriterState *statePtr, Tk_PhotoImageBlock *blockPtr);
-
-static int ReadValue(GifWriterState *statePtr);
-
-static int no_bits(int colors);
-
-static int
-ChnWrite (interp, filename, format, blockPtr)
- Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
- const char *filename;
- Tcl_Obj *format;
- Tk_PhotoImageBlock *blockPtr;
-{
- Tcl_Channel chan = NULL;
- tkimg_MFile handle;
- int result;
-
- chan = tkimg_OpenFileChannel(interp, filename, 0644);
- if (!chan) {
- return TCL_ERROR;
- }
-
- handle.data = (char *) chan;
- handle.state = IMG_CHAN;
-
- result = CommonWrite(interp, &handle, format, blockPtr);
- if (Tcl_Close(interp, chan) == TCL_ERROR) {
- return TCL_ERROR;
- }
- return result;
-}
-
-static int StringWrite(
- Tcl_Interp *interp,
- Tcl_Obj *format,
- Tk_PhotoImageBlock *blockPtr
-) {
- int result;
- tkimg_MFile handle;
- Tcl_DString data;
-
- Tcl_DStringInit(&data);
- Tcl_DStringSetLength(&data, 1024);
- tkimg_WriteInit(&data, &handle);
-
- result = CommonWrite(interp, &handle, format, blockPtr);
- tkimg_Putc(IMG_DONE, &handle);
-
- if (result == TCL_OK) {
- Tcl_DStringResult(interp, &data);
- } else {
- Tcl_DStringFree(&data);
- }
- return result;
-}
-
-static int
-CommonWrite(interp, handle, format, blockPtr)
- Tcl_Interp *interp;
- tkimg_MFile *handle;
- Tcl_Obj *format;
- Tk_PhotoImageBlock *blockPtr;
-{
- GifWriterState state;
- int resolution;
- long numcolormap;
-
- long width,height,x;
- unsigned char c;
- unsigned int top,left;
- int num;
-
- top = 0;
- left = 0;
-
- state.pixelSize=blockPtr->pixelSize;
- state.greenOffset=blockPtr->offset[1]-blockPtr->offset[0];
- state.blueOffset=blockPtr->offset[2]-blockPtr->offset[0];
- state.alphaOffset = blockPtr->offset[0];
- if (state.alphaOffset < blockPtr->offset[2]) {
- state.alphaOffset = blockPtr->offset[2];
- }
- if (++state.alphaOffset < state.pixelSize) {
- state.alphaOffset -= blockPtr->offset[0];
- } else {
- state.alphaOffset = 0;
- }
-
- tkimg_Write(handle, (const char *) (state.alphaOffset ? GIF89a:GIF87a), 6);
-
- for (x=0;x<MAXCOLORMAPSIZE;x++) {
- state.mapa[x][CM_RED] = 255;
- state.mapa[x][CM_GREEN] = 255;
- state.mapa[x][CM_BLUE] = 255;
- }
-
-
- width=blockPtr->width;
- height=blockPtr->height;
- state.pixelo=blockPtr->pixelPtr + blockPtr->offset[0];
- state.pixelPitch=blockPtr->pitch;
- if ((num=savemap(&state,blockPtr))<0) {
- Tcl_AppendResult(interp, "too many colors", (char *) NULL);
- return TCL_ERROR;
- }
- if (state.num<3) state.num=3;
- c=LSB(width);
- tkimg_Putc(c,handle);
- c=MSB(width);
- tkimg_Putc(c,handle);
- c=LSB(height);
- tkimg_Putc(c,handle);
- c=MSB(height);
- tkimg_Putc(c,handle);
-
- c= (1 << 7) | (no_bits(num) << 4) | (no_bits(num));
- tkimg_Putc(c,handle);
- resolution = no_bits(num)+1;
-
- numcolormap=1 << resolution;
-
- /* background color */
-
- tkimg_Putc(0,handle);
-
- /* zero for future expansion */
-
- tkimg_Putc(0,handle);
-
- for (x=0; x<numcolormap ;x++) {
- tkimg_Putc(state.mapa[x][CM_RED],handle);
- tkimg_Putc(state.mapa[x][CM_GREEN],handle);
- tkimg_Putc(state.mapa[x][CM_BLUE],handle);
- }
-
- /*
- * Write out extension for transparent colour index, if necessary.
- */
-
- if (state.alphaOffset) {
- tkimg_Write(handle, "!\371\4\1\0\0\0", 8);
- }
-
- c = GIF_START;
- tkimg_Putc(c,handle);
- c=LSB(top);
- tkimg_Putc(c,handle);
- c=MSB(top);
- tkimg_Putc(c,handle);
- c=LSB(left);
- tkimg_Putc(c,handle);
- c=MSB(left);
- tkimg_Putc(c,handle);
-
- c=LSB(width);
- tkimg_Putc(c,handle);
- c=MSB(width);
- tkimg_Putc(c,handle);
-
- c=LSB(height);
- tkimg_Putc(c,handle);
- c=MSB(height);
- tkimg_Putc(c,handle);
-
- c=0;
- tkimg_Putc(c,handle);
- c=resolution;
- tkimg_Putc(c,handle);
-
- state.ssize = state.rsize = blockPtr->width;
- state.csize = blockPtr->height;
- compress(&state, resolution+1, handle, ReadValue);
-
- tkimg_Putc(0,handle);
- c = GIF_TERMINATOR;
- tkimg_Putc(c,handle);
-
- return TCL_OK;
-}
-
-static int
-color(statePtr, red, green, blue)
- GifWriterState *statePtr;
- int red;
- int green;
- int blue;
-{
- int x;
- for (x=(statePtr->alphaOffset != 0);x<=MAXCOLORMAPSIZE;x++) {
- if ((statePtr->mapa[x][CM_RED]==red) && (statePtr->mapa[x][CM_GREEN]==green) &&
- (statePtr->mapa[x][CM_BLUE]==blue)) {
- return x;
- }
- }
- return -1;
-}
-
-
-static int
-nuevo(statePtr, red, green, blue)
- GifWriterState *statePtr;
- int red,green,blue;
-{
- int x;
- for (x=(statePtr->alphaOffset != 0);x<statePtr->num;x++) {
- if ((statePtr->mapa[x][CM_RED]==red) && (statePtr->mapa[x][CM_GREEN]==green) &&
- (statePtr->mapa[x][CM_BLUE]==blue)) {
- return 0;
- }
- }
- return 1;
-}
-
-static int
-savemap(statePtr, blockPtr)
- GifWriterState *statePtr;
- Tk_PhotoImageBlock *blockPtr;
-{
- unsigned char *colores;
- int x,y;
- unsigned char red,green,blue;
-
- if (statePtr->alphaOffset) {
- statePtr->num = 1;
- statePtr->mapa[0][CM_RED] = 0xd9;
- statePtr->mapa[0][CM_GREEN] = 0xd9;
- statePtr->mapa[0][CM_BLUE] = 0xd9;
- } else {
- statePtr->num = 0;
- }
-
- for(y=0;y<blockPtr->height;y++) {
- colores=blockPtr->pixelPtr + blockPtr->offset[0]
- + y * blockPtr->pitch;
- for(x=0;x<blockPtr->width;x++) {
- if (!statePtr->alphaOffset || (colores[statePtr->alphaOffset] != 0)) {
- red = colores[0];
- green = colores[statePtr->greenOffset];
- blue = colores[statePtr->blueOffset];
- if (nuevo(statePtr, red, green, blue)) {
- if (statePtr->num>255)
- return -1;
-
- statePtr->mapa[statePtr->num][CM_RED]=red;
- statePtr->mapa[statePtr->num][CM_GREEN]=green;
- statePtr->mapa[statePtr->num][CM_BLUE]=blue;
- statePtr->num++;
- }
- }
- colores += statePtr->pixelSize;
- }
- }
- return statePtr->num;
-}
-
-static int
-ReadValue(statePtr)
- GifWriterState *statePtr;
-{
- unsigned int col;
-
- if (statePtr->csize == 0) {
- return EOF;
- }
- if (statePtr->alphaOffset && (statePtr->pixelo[statePtr->alphaOffset]==0)) {
- col = 0;
- } else {
- col = color(statePtr, statePtr->pixelo[0],statePtr->pixelo[statePtr->greenOffset],statePtr->pixelo[statePtr->blueOffset]);
- }
- statePtr->pixelo += statePtr->pixelSize;
- if (--statePtr->ssize <= 0) {
- statePtr->ssize = statePtr->rsize;
- statePtr->csize--;
- statePtr->pixelo += statePtr->pixelPitch - (statePtr->rsize * statePtr->pixelSize);
- }
-
- return col;
-}
-
-/*
- * Return the number of bits ( -1 ) to represent a given
- * number of colors ( ex: 256 colors => 7 ).
- */
-static int
-no_bits( colors )
-int colors;
-{
- register int bits = 0;
-
- colors--;
- while ( colors >> bits ) {
- bits++;
- }
-
- return (bits-1);
-}
-
-
-/*
- *
- * GIF Image compression - modified 'compress'
- *
- * Based on: compress.c - File compression ala IEEE Computer, June 1984.
- *
- * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
- * Jim McKie (decvax!mcvax!jim)
- * Steve Davies (decvax!vax135!petsd!peora!srd)
- * Ken Turkowski (decvax!decwrl!turtlevax!ken)
- * James A. Woods (decvax!ihnp4!ames!jaw)
- * Joe Orost (decvax!vax135!petsd!joe)
- *
- */
-
-#define MAXCODE(n_bits) (((long) 1 << (n_bits)) - 1)
-
-typedef struct {
- int n_bits; /* number of bits/code */
- long maxcode; /* maximum code, given n_bits */
- int htab[HSIZE];
- unsigned int codetab[HSIZE];
-
- long hsize; /* for dynamic table sizing */
-
-/*
- * To save much memory, we overlay the table used by compress() with those
- * used by decompress(). The tab_prefix table is the same size and type
- * as the codetab. The tab_suffix table needs 2**GIFBITS characters. We
- * get this from the beginning of htab. The output stack uses the rest
- * of htab, and contains characters. There is plenty of room for any
- * possible stack (stack used to be 8000 characters).
- */
-
- int free_ent; /* first unused entry */
-
-/*
- * block compression parameters -- after all codes are used up,
- * and compression rate changes, start over.
- */
- int clear_flg;
-
- int offset;
- unsigned int in_count; /* length of input */
- unsigned int out_count; /* # of codes output (for debugging) */
-
-/*
- * compress stdin to stdout
- *
- * Algorithm: use open addressing double hashing (no chaining) on the
- * prefix code / next character combination. We do a variant of Knuth's
- * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
- * secondary probe. Here, the modular division first probe is gives way
- * to a faster exclusive-or manipulation. Also do block compression with
- * an adaptive reset, whereby the code table is cleared when the compression
- * ratio decreases, but after the table fills. The variable-length output
- * codes are re-sized at this point, and a special CLEAR code is generated
- * for the decompressor. Late addition: construct the table according to
- * file size for noticeable speed improvement on small files. Please direct
- * questions about this implementation to ames!jaw.
- */
-
- int g_init_bits;
- tkimg_MFile *g_outfile;
-
- int ClearCode;
- int EOFCode;
-
- unsigned long cur_accum;
- int cur_bits;
-
-/*
- * Number of characters so far in this 'packet'
- */
- int a_count;
-
-/*
- * Define the storage for the packet accumulator
- */
- unsigned char accum[256];
-} GIFState_t;
-
-static void output(GIFState_t *statePtr, long code);
-static void cl_block(GIFState_t *statePtr);
-static void cl_hash(GIFState_t *statePtr, int hsize);
-static void char_init(GIFState_t *statePtr);
-static void char_out(GIFState_t *statePtr, int c);
-static void flush_char(GIFState_t *statePtr);
-
-static void compress(statePtr, init_bits, handle, readValue)
- GifWriterState *statePtr;
- int init_bits;
- tkimg_MFile *handle;
- ifunptr readValue;
-{
- register long fcode;
- register long i = 0;
- register int c;
- register long ent;
- register long disp;
- register long hsize_reg;
- register int hshift;
- GIFState_t state;
-
- memset(&state, 0, sizeof(state));
- /*
- * Set up the globals: g_init_bits - initial number of bits
- * g_outfile - pointer to output file
- */
- state.g_init_bits = init_bits;
- state.g_outfile = handle;
-
- /*
- * Set up the necessary values
- */
- state.offset = 0;
- state.hsize = HSIZE;
- state.out_count = 0;
- state.clear_flg = 0;
- state.in_count = 1;
- state.maxcode = MAXCODE(state.n_bits = state.g_init_bits);
-
- state.ClearCode = (1 << (init_bits - 1));
- state.EOFCode = state.ClearCode + 1;
- state.free_ent = state.ClearCode + 2;
-
- char_init(&state);
-
- ent = readValue(statePtr);
-
- hshift = 0;
- for ( fcode = (long) state.hsize; fcode < 65536L; fcode *= 2L )
- hshift++;
- hshift = 8 - hshift; /* set hash code range bound */
-
- hsize_reg = state.hsize;
- cl_hash(&state, (int) hsize_reg); /* clear hash table */
-
- output(&state, (long)state.ClearCode);
-
-#ifdef SIGNED_COMPARE_SLOW
- while ( (c = readValue(statePtr) ) != (unsigned) EOF ) {
-#else
- while ( (c = readValue(statePtr)) != EOF ) {
-#endif
-
- state.in_count++;
-
- fcode = (long) (((long) c << GIFBITS) + ent);
- i = (((long)c << hshift) ^ ent); /* xor hashing */
-
- if (state.htab[i] == fcode) {
- ent = state.codetab[i];
- continue;
- } else if ( (long) state.htab[i] < 0 ) /* empty slot */
- goto nomatch;
- disp = hsize_reg - i; /* secondary hash (after G. Knott) */
- if ( i == 0 )
- disp = 1;
-probe:
- if ( (i -= disp) < 0 )
- i += hsize_reg;
-
- if (state.htab[i] == fcode) {
- ent = state.codetab[i];
- continue;
- }
- if ( (long) state.htab[i] > 0 )
- goto probe;
-nomatch:
- output (&state, (long) ent);
- state.out_count++;
- ent = c;
-#ifdef SIGNED_COMPARE_SLOW
- if ( (unsigned) free_ent < (unsigned) ((long)1 << GIFBITS)) {
-#else
- if (state.free_ent < ((long)1 << GIFBITS)) {
-#endif
- state.codetab[i] = state.free_ent++; /* code -> hashtable */
- state.htab[i] = fcode;
- } else
- cl_block(&state);
- }
- /*
- * Put out the final code.
- */
- output(&state, (long)ent);
- state.out_count++;
- output(&state, (long) state.EOFCode);
-
- return;
-}
-
-/*****************************************************************
- * TAG( output )
- *
- * Output the given code.
- * Inputs:
- * code: A n_bits-bit integer. If == -1, then EOF. This assumes
- * that n_bits =< (long) wordsize - 1.
- * Outputs:
- * Outputs code to the file.
- * Assumptions:
- * Chars are 8 bits long.
- * Algorithm:
- * Maintain a GIFBITS character long buffer (so that 8 codes will
- * fit in it exactly). Use the VAX insv instruction to insert each
- * code in turn. When the buffer fills up empty it and start over.
- */
-
-static const
-unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
- 0x001F, 0x003F, 0x007F, 0x00FF,
- 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
- 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
-
-static void
-output(statePtr, code)
- GIFState_t *statePtr;
- long code;
-{
- statePtr->cur_accum &= masks[statePtr->cur_bits];
-
- if (statePtr->cur_bits > 0) {
- statePtr->cur_accum |= ((long) code << statePtr->cur_bits);
- } else {
- statePtr->cur_accum = code;
- }
-
- statePtr->cur_bits += statePtr->n_bits;
-
- while (statePtr->cur_bits >= 8 ) {
- char_out(statePtr, (unsigned int)(statePtr->cur_accum & 0xff));
- statePtr->cur_accum >>= 8;
- statePtr->cur_bits -= 8;
- }
-
- /*
- * If the next entry is going to be too big for the code size,
- * then increase it, if possible.
- */
-
- if ((statePtr->free_ent > statePtr->maxcode)|| statePtr->clear_flg ) {
- if (statePtr->clear_flg) {
- statePtr->maxcode = MAXCODE(statePtr->n_bits = statePtr->g_init_bits);
- statePtr->clear_flg = 0;
- } else {
- statePtr->n_bits++;
- if (statePtr->n_bits == GIFBITS) {
- statePtr->maxcode = (long)1 << GIFBITS;
- } else {
- statePtr->maxcode = MAXCODE(statePtr->n_bits);
- }
- }
- }
-
- if (code == statePtr->EOFCode) {
- /*
- * At EOF, write the rest of the buffer.
- */
- while (statePtr->cur_bits > 0) {
- char_out(statePtr, (unsigned int)(statePtr->cur_accum & 0xff));
- statePtr->cur_accum >>= 8;
- statePtr->cur_bits -= 8;
- }
- flush_char(statePtr);
- }
-}
-
-/*
- * Clear out the hash table
- */
-static void
-cl_block(statePtr) /* table clear for block compress */
- GIFState_t *statePtr;
-{
-
- cl_hash (statePtr, (int) statePtr->hsize);
- statePtr->free_ent = statePtr->ClearCode + 2;
- statePtr->clear_flg = 1;
-
- output(statePtr, (long) statePtr->ClearCode);
-}
-
-static void
-cl_hash(statePtr, hsize) /* reset code table */
- GIFState_t *statePtr;
- int hsize;
-{
- register int *htab_p = statePtr->htab+hsize;
- register long i;
- register long m1 = -1;
-
- i = hsize - 16;
- do { /* might use Sys V memset(3) here */
- *(htab_p-16) = m1;
- *(htab_p-15) = m1;
- *(htab_p-14) = m1;
- *(htab_p-13) = m1;
- *(htab_p-12) = m1;
- *(htab_p-11) = m1;
- *(htab_p-10) = m1;
- *(htab_p-9) = m1;
- *(htab_p-8) = m1;
- *(htab_p-7) = m1;
- *(htab_p-6) = m1;
- *(htab_p-5) = m1;
- *(htab_p-4) = m1;
- *(htab_p-3) = m1;
- *(htab_p-2) = m1;
- *(htab_p-1) = m1;
- htab_p -= 16;
- } while ((i -= 16) >= 0);
-
- for (i += 16; i > 0; i--) {
- *--htab_p = m1;
- }
-}
-
-
-/******************************************************************************
- *
- * GIF Specific routines
- *
- ******************************************************************************/
-
-/*
- * Set up the 'byte output' routine
- */
-static void
-char_init(statePtr)
- GIFState_t *statePtr;
-{
- statePtr->a_count = 0;
- statePtr->cur_accum = 0;
- statePtr->cur_bits = 0;
-}
-
-/*
- * Add a character to the end of the current packet, and if it is 254
- * characters, flush the packet to disk.
- */
-static void
-char_out(statePtr, c)
- GIFState_t *statePtr;
- int c;
-{
- statePtr->accum[statePtr->a_count++] = c;
- if (statePtr->a_count >= 254) {
- flush_char(statePtr);
- }
-}
-
-/*
- * Flush the packet to disk, and reset the accumulator
- */
-static void
-flush_char(statePtr)
- GIFState_t *statePtr;
-{
- unsigned char c;
- if (statePtr->a_count > 0) {
- c = statePtr->a_count;
- tkimg_Write(statePtr->g_outfile, (const char *) &c, 1);
- tkimg_Write(statePtr->g_outfile, (const char *) statePtr->accum, statePtr->a_count);
- statePtr->a_count = 0;
- }
-}
-
-/* The End */