diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2010-07-18 23:58:17 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2010-07-18 23:58:17 (GMT) |
commit | aa15eba7248d4f511d831e0536eb937cedb885d9 (patch) | |
tree | cb07b940dd34677f3356dd9b5b1b50091b05d66f | |
parent | a5b009796383e0a829c96ed6ac24c3b035f55fde (diff) | |
download | tk-aa15eba7248d4f511d831e0536eb937cedb885d9.zip tk-aa15eba7248d4f511d831e0536eb937cedb885d9.tar.gz tk-aa15eba7248d4f511d831e0536eb937cedb885d9.tar.bz2 |
* generic/tkImgGIF.c (StringWriteGIF): Added ability to write a GIF to
a string (as a byte array, of course) following comments on c.l.t by
Aric Bills. Also improved readability of some of the function and
field names in this file.
-rw-r--r-- | ChangeLog | 56 | ||||
-rw-r--r-- | generic/tkImgGIF.c | 688 |
2 files changed, 402 insertions, 342 deletions
@@ -1,36 +1,44 @@ +2010-07-19 Donal K. Fellows <dkf@users.sf.net> + + * generic/tkImgGIF.c (StringWriteGIF): Added ability to write a GIF to + a string (as a byte array, of course) following comments on c.l.t by + Aric Bills. Also improved readability of some of the function and + field names in this file. + 2010-07-16 Jan Nijtmans <nijtmans@users.sf.net> - * generic/tkDecls.h [Tcl Bug 3029891] Functions that don't belong in the - stub table (Tk part, not really removed from the stub table, just disabled) - * generic/tkMain.c [Bug 3027438] Tk_Main calls Tcl_CreateInterp before - * generic/tk.h Tcl_FindExecutable + * generic/tkDecls.h: [Tcl Bug 3029891]: Functions that don't belong in + the stub table (Tk part, not really removed from the stub table, just + disabled) + * generic/tkMain.c: [Bug 3027438]: Tk_Main calls Tcl_CreateInterp + * generic/tk.h: before Tcl_FindExecutable 2010-07-06 Andreas Kupries <andreask@activestate.com> - * doc/text.n: Fixed minor typo in the description of 'text - delete', as reported by <eee@users.sf.net> on the chat. + * doc/text.n: Fixed minor typo in the description of 'text delete', as + reported by <eee@users.sf.net> on the chat. 2010-07-01 Jan Nijtmans <nijtmans@users.sf.net> - * win/rules.vc [Bugs #3020677] wish can't link reg1.2 + * win/rules.vc: [Bug 3020677]: wish can't link reg1.2 2010-06-22 Anton Kovalenko <a_kovalenko@users.sf.net> - * generic/tkPlace.c: [Patch #3019624] modify "place" command, - making it get main window through ClientData (like grid or pack - do), instead of calling Tk_MainWindow(interp). - * generic/tkWindow.c: modify "place" entry in commands[], - turn on passMainWindow flag. + * generic/tkPlace.c: [Patch 3019624]: modify "place" command, making + it get main window through ClientData (like grid or pack do), instead + of calling Tk_MainWindow(interp). + * generic/tkWindow.c: modify "place" entry in commands[], turn on + passMainWindow flag. 2010-06-22 Jan Nijtmans <nijtmans@users.sf.net> - * generic/ttk/ttkGenStubs.tcl [Bug #3019363] "make genstubs" failure - * generic/ttk/ttkDecls.h (regenerated) - * generic/ttk/ttkTheme.c Unnecessary type cast + * generic/ttk/ttkGenStubs.tcl: [Bug 3019363]: "make genstubs" failure + * generic/ttk/ttkDecls.h: (regenerated) + * generic/ttk/ttkTheme.c: Unnecessary type cast 2010-06-21 Jan Nijtmans <nijtmans@users.sf.net> - * generic/tkInt.decls [Patch #2999889] TkCopyAndGlobalEval obsolete + * generic/tkInt.decls: [Patch 2999889]: TkCopyAndGlobalEval obsolete * generic/tkIntDecls.h * generic/tkBind.c * generic/tkStubInit.c @@ -38,21 +46,21 @@ 2010-06-19 Joe English <jenglish@users.sourceforge.net> * win/tkWinScrlbr.c, carbon/tkMacOSXScrlbr.c: Replace binding - procedures with ordinary event handlers [Patch 3009998]. + procedures with ordinary event handlers [Patch 3009998]. * generic/tkBind.c, generic/tk.h, generic/tkInt.h, - generic/tkInt.decls: Simplifications enabled by previous change: - TkCreateBindingProcedure() and associated machinery - no longer needed; TkBindDeadWindow() no longer needed; - TK_DEFER_MODAL_LOOP and associated machinery no longer needed. + * generic/tkInt.decls: Simplifications enabled by previous change: + TkCreateBindingProcedure() and associated machinery no longer needed; + TkBindDeadWindow() no longer needed; TK_DEFER_MODAL_LOOP and + associated machinery no longer needed. * generic/tkTest.c, tests/bind.test: Tests related to C binding - procedures no longer needed. + procedures no longer needed. * generic/tkWindow.c: TkBindDeadWindow() no longer needed. * generic/tkIntDecls.h, generic/tkStubInit.c: Regenerated. 2010-06-15 Joe English <jenglish@users.sourceforge.net> - * library/ttk/ttk.tcl: Bump dummy [package ifneeded tile] version - to 0.8.6; see [Bug 3016598]. + * library/ttk/ttk.tcl: Bump dummy [package ifneeded tile] version to + 0.8.6; see [Bug 3016598]. 2010-06-15 Donal K. Fellows <dkf@users.sf.net> diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c index b7bb956..0ece066 100644 --- a/generic/tkImgGIF.c +++ b/generic/tkImgGIF.c @@ -11,7 +11,7 @@ * Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1997 Australian National University - * Copyright (c) 2005 Donal K. Fellows + * Copyright (c) 2005-2010 Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -29,7 +29,7 @@ * | provided "as is" without express or implied warranty. | * +--------------------------------------------------------------------+ * - * RCS: @(#) $Id: tkImgGIF.c,v 1.47 2010/04/23 08:32:56 nijtmans Exp $ + * RCS: @(#) $Id: tkImgGIF.c,v 1.48 2010/07/18 23:58:17 dkf Exp $ */ #include "tkInt.h" @@ -109,6 +109,14 @@ typedef struct { } GIFImageConfig; /* + * Type of a function used to do the writing to a file or buffer when + * serializing in the GIF format. + */ + +typedef int (WriteBytesFunc) (ClientData clientData, const char *bytes, + int byteCount); + +/* * The format record for the GIF file format: */ @@ -127,8 +135,11 @@ static int StringReadGIF(Tcl_Interp *interp, Tcl_Obj *dataObj, int srcX, int srcY); static int FileWriteGIF(Tcl_Interp *interp, const char *filename, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr); -static int CommonWriteGIF(Tcl_Interp *interp, Tcl_Channel handle, - Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr); +static int StringWriteGIF(Tcl_Interp *interp, Tcl_Obj *format, + Tk_PhotoImageBlock *blockPtr); +static int CommonWriteGIF(Tcl_Interp *interp, ClientData clientData, + WriteBytesFunc *writeProc, Tcl_Obj *format, + Tk_PhotoImageBlock *blockPtr); Tk_PhotoImageFormat tkImgFmtGIF = { "gif", /* name */ @@ -137,7 +148,7 @@ Tk_PhotoImageFormat tkImgFmtGIF = { FileReadGIF, /* fileReadProc */ StringReadGIF, /* stringReadProc */ FileWriteGIF, /* fileWriteProc */ - NULL, /* stringWriteProc */ + StringWriteGIF, /* stringWriteProc */ NULL }; @@ -186,6 +197,135 @@ static int Mgetc(MFile *handle); static int char64(int c); static void mInit(unsigned char *string, MFile *handle, int length); + +/* + * 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 */ + +#define DEFAULT_BACKGROUND_VALUE 0xD9 + +typedef struct { + int ssize; + int csize; + int rsize; + unsigned char *pixelOffset; + int pixelSize; + int pixelPitch; + int greenOffset; + int blueOffset; + int alphaOffset; + int num; + unsigned char mapa[MAXCOLORMAPSIZE][3]; +} GifWriterState; + +typedef int (* ifunptr) (GifWriterState *statePtr); + +/* + * Support for compression of GIFs. + */ + +#define MAXCODE(numBits) (((long) 1 << (numBits)) - 1) + +#ifdef SIGNED_COMPARE_SLOW +#define U(x) ((unsigned) (x)) +#else +#define U(x) (x) +#endif + +typedef struct { + int numBits; /* Number of bits/code. */ + long maxCode; /* Maximum code, given numBits. */ + int hashTable[HSIZE]; + unsigned int codeTable[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 codeTable. The tab_suffix table needs 2**GIFBITS characters. We get + * this from the beginning of hashTable. The output stack uses the rest of + * hashTable, and contains characters. There is plenty of room for any + * possible stack (stack used to be 8000 characters). + */ + + int freeEntry; /* First unused entry. */ + + /* + * Block compression parameters. After all codes are used up, and + * compression rate changes, start over. + */ + + int clearFlag; + + int offset; + unsigned int inCount; /* Length of input */ + unsigned int outCount; /* # of codes output (for debugging) */ + + /* + * 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 initialBits; + ClientData destination; + WriteBytesFunc *writeProc; + + int clearCode; + int eofCode; + + unsigned long currentAccumulated; + int currentBits; + + /* + * Number of characters so far in this 'packet' + */ + + int accumulatedByteCount; + + /* + * Define the storage for the packet accumulator + */ + + unsigned char packetAccumulator[256]; +} GIFState_t; + +/* + * Definition of new functions to write GIFs + */ + +static int ColorNumber(GifWriterState *statePtr, + int red, int green, int blue); +static void Compress(int initBits, ClientData handle, + WriteBytesFunc *writeProc, ifunptr readValue, + GifWriterState *statePtr); +static int IsNewColor(GifWriterState *statePtr, + int red, int green, int blue); +static void SaveMap(GifWriterState *statePtr, + Tk_PhotoImageBlock *blockPtr); +static int ReadValue(GifWriterState *statePtr); +static WriteBytesFunc WriteToChannel; +static WriteBytesFunc WriteToByteArray; +static void Output(GIFState_t *statePtr, long code); +static void ClearForBlock(GIFState_t *statePtr); +static void ClearHashTable(GIFState_t *statePtr, int hSize); +static void CharInit(GIFState_t *statePtr); +static void CharOut(GIFState_t *statePtr, int c); +static void FlushChar(GIFState_t *statePtr); /* *---------------------------------------------------------------------- @@ -1424,51 +1564,12 @@ Fread( * 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. + * 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(int initBits, Tcl_Channel handle, - ifunptr readValue, GifWriterState *statePtr); -static int nuevo(GifWriterState *statePtr, - int red, int green, int blue); -static void savemap(GifWriterState *statePtr, - Tk_PhotoImageBlock *blockPtr); -static int ReadValue(GifWriterState *statePtr); static int FileWriteGIF( @@ -1490,18 +1591,65 @@ FileWriteGIF( return TCL_ERROR; } - result = CommonWriteGIF(interp, chan, format, blockPtr); + result = CommonWriteGIF(interp, chan, WriteToChannel, format, blockPtr); if (Tcl_Close(interp, chan) == TCL_ERROR) { return TCL_ERROR; } return result; } + +static int +StringWriteGIF( + Tcl_Interp *interp, /* Interpreter to use for reporting errors and + * returning the GIF data. */ + Tcl_Obj *format, + Tk_PhotoImageBlock *blockPtr) +{ + int result; + Tcl_Obj *objPtr = Tcl_NewObj(); + + Tcl_IncrRefCount(objPtr); + result = CommonWriteGIF(interp, objPtr, WriteToByteArray, format, + blockPtr); + if (result == TCL_OK) { + Tcl_SetObjResult(interp, objPtr); + } + Tcl_DecrRefCount(objPtr); + return result; +} + +static int +WriteToChannel( + ClientData clientData, + const char *bytes, + int byteCount) +{ + Tcl_Channel handle = clientData; + + return Tcl_Write(handle, bytes, byteCount); +} + +static int +WriteToByteArray( + ClientData clientData, + const char *bytes, + int byteCount) +{ + Tcl_Obj *objPtr = clientData; + Tcl_Obj *tmpObj = Tcl_NewByteArrayObj((unsigned char *) bytes, byteCount); + + Tcl_IncrRefCount(tmpObj); + Tcl_AppendObjToObj(objPtr, tmpObj); + Tcl_DecrRefCount(tmpObj); + return byteCount; +} static int CommonWriteGIF( Tcl_Interp *interp, - Tcl_Channel handle, + ClientData handle, + WriteBytesFunc *writeProc, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr) { @@ -1529,7 +1677,7 @@ CommonWriteGIF( state.alphaOffset = 0; } - Tcl_Write(handle, (char *) (state.alphaOffset ? GIF89a : GIF87a), 6); + writeProc(handle, (char *) (state.alphaOffset ? GIF89a : GIF87a), 6); for (x = 0; x < MAXCOLORMAPSIZE ;x++) { state.mapa[x][CM_RED] = 255; @@ -1539,9 +1687,9 @@ CommonWriteGIF( width = blockPtr->width; height = blockPtr->height; - state.pixelo = blockPtr->pixelPtr + blockPtr->offset[0]; + state.pixelOffset = blockPtr->pixelPtr + blockPtr->offset[0]; state.pixelPitch = blockPtr->pitch; - savemap(&state, blockPtr); + SaveMap(&state, blockPtr); if (state.num >= MAXCOLORMAPSIZE) { Tcl_AppendResult(interp, "too many colors", NULL); return TCL_ERROR; @@ -1550,20 +1698,20 @@ CommonWriteGIF( state.num = 2; } c = LSB(width); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = MSB(width); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = LSB(height); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = MSB(height); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); resolution = 0; while (state.num >> resolution) { resolution++; } c = 111 + resolution * 17; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); state.num = 1 << resolution; @@ -1572,21 +1720,21 @@ CommonWriteGIF( */ c = 0; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); /* * Zero for future expansion. */ - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); for (x = 0; x < state.num; x++) { c = state.mapa[x][CM_RED]; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = state.mapa[x][CM_GREEN]; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = state.mapa[x][CM_BLUE]; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); } /* @@ -1595,50 +1743,50 @@ CommonWriteGIF( if (state.alphaOffset) { c = GIF_EXTENSION; - Tcl_Write(handle, (char *) &c, 1); - Tcl_Write(handle, "\371\4\1\0\0\0", 7); + writeProc(handle, (char *) &c, 1); + writeProc(handle, "\371\4\1\0\0\0", 7); } c = GIF_START; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = LSB(top); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = MSB(top); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = LSB(left); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = MSB(left); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = LSB(width); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = MSB(width); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = LSB(height); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = MSB(height); - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = 0; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = resolution; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); state.ssize = state.rsize = blockPtr->width; state.csize = blockPtr->height; - compress(resolution+1, handle, ReadValue, &state); + Compress(resolution+1, handle, writeProc, ReadValue, &state); c = 0; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); c = GIF_TERMINATOR; - Tcl_Write(handle, (char *) &c, 1); + writeProc(handle, (char *) &c, 1); return TCL_OK; } static int -color( +ColorNumber( GifWriterState *statePtr, int red, int green, int blue) { @@ -1655,7 +1803,7 @@ color( } static int -nuevo( +IsNewColor( GifWriterState *statePtr, int red, int green, int blue) { @@ -1672,7 +1820,7 @@ nuevo( } static void -savemap( +SaveMap( GifWriterState *statePtr, Tk_PhotoImageBlock *blockPtr) { @@ -1682,9 +1830,9 @@ savemap( if (statePtr->alphaOffset) { statePtr->num = 0; - statePtr->mapa[0][CM_RED] = 0xd9; - statePtr->mapa[0][CM_GREEN] = 0xd9; - statePtr->mapa[0][CM_BLUE] = 0xd9; + statePtr->mapa[0][CM_RED] = DEFAULT_BACKGROUND_VALUE; + statePtr->mapa[0][CM_GREEN] = DEFAULT_BACKGROUND_VALUE; + statePtr->mapa[0][CM_BLUE] = DEFAULT_BACKGROUND_VALUE; } else { statePtr->num = -1; } @@ -1696,7 +1844,7 @@ savemap( red = colores[0]; green = colores[statePtr->greenOffset]; blue = colores[statePtr->blueOffset]; - if (nuevo(statePtr, red, green, blue)) { + if (IsNewColor(statePtr, red, green, blue)) { statePtr->num++; if (statePtr->num >= MAXCOLORMAPSIZE) { return; @@ -1720,18 +1868,19 @@ ReadValue( if (statePtr->csize == 0) { return EOF; } - if (statePtr->alphaOffset && (statePtr->pixelo[statePtr->alphaOffset]==0)) { + if (statePtr->alphaOffset + && (statePtr->pixelOffset[statePtr->alphaOffset]==0)) { col = 0; } else { - col = color(statePtr, statePtr->pixelo[0], - statePtr->pixelo[statePtr->greenOffset], - statePtr->pixelo[statePtr->blueOffset]); + col = ColorNumber(statePtr, statePtr->pixelOffset[0], + statePtr->pixelOffset[statePtr->greenOffset], + statePtr->pixelOffset[statePtr->blueOffset]); } - statePtr->pixelo += statePtr->pixelSize; + statePtr->pixelOffset += statePtr->pixelSize; if (--statePtr->ssize <= 0) { statePtr->ssize = statePtr->rsize; statePtr->csize--; - statePtr->pixelo += statePtr->pixelPitch + statePtr->pixelOffset += statePtr->pixelPitch - (statePtr->rsize * statePtr->pixelSize); } @@ -1739,7 +1888,7 @@ ReadValue( } /* - * GIF Image compression - modified 'compress' + * GIF Image compression - modified 'Compress' * * Based on: compress.c - File compression ala IEEE Computer, June 1984. * @@ -1750,192 +1899,98 @@ ReadValue( * 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; - Tcl_Channel 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(int initBits, Tcl_Channel handle, - ifunptr readValue, GifWriterState *statePtr); static void -compress( - int init_bits, - Tcl_Channel handle, +Compress( + int initialBits, + ClientData handle, + WriteBytesFunc *writeProc, ifunptr readValue, GifWriterState *statePtr) { - register long fcode; - register long i = 0; - register int c; - register long ent; - register long disp; - register long hsize_reg; - register int hshift; + long fcode, ent, disp, hSize, i = 0; + int c, 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 + * Set up the globals: initialBits - initial number of bits + * outChannel - pointer to output file */ - state.g_init_bits = init_bits; - state.g_outfile = handle; + state.initialBits = initialBits; + state.destination = handle; + state.writeProc = writeProc; /* * 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); + state.hSize = HSIZE; + state.outCount = 0; + state.clearFlag = 0; + state.inCount = 1; + state.maxCode = MAXCODE(state.numBits = state.initialBits); + state.clearCode = 1 << (initialBits - 1); + state.eofCode = state.clearCode + 1; + state.freeEntry = state.clearCode + 2; + CharInit(&state); ent = readValue(statePtr); hshift = 0; - for (fcode = (long) state.hsize; fcode < 65536L; fcode *= 2L) { + for (fcode = (long) state.hSize; fcode < 65536L; fcode *= 2L) { hshift++; } - hshift = 8 - hshift; /* set hash code range bound */ + hshift = 8 - hshift; /* Set hash code range bound */ - hsize_reg = state.hsize; - cl_hash(&state, (int) hsize_reg); /* clear hash table */ + hSize = state.hSize; + ClearHashTable(&state, (int) hSize); /* Clear hash table */ - output(&state, (long) state.ClearCode); + 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++; + while (U(c = readValue(statePtr)) != U(EOF)) { + state.inCount++; fcode = (long) (((long) c << GIFBITS) + ent); - i = (((long)c << hshift) ^ ent); /* xor hashing */ + i = ((long)c << hshift) ^ ent; /* XOR hashing */ - if (state.htab[i] == fcode) { - ent = state.codetab[i]; + if (state.hashTable[i] == fcode) { + ent = state.codeTable[i]; continue; - } else if ((long) state.htab[i] < 0) { /* empty slot */ + } else if ((long) state.hashTable[i] < 0) { /* Empty slot */ goto nomatch; } - disp = hsize_reg - i; /* secondary hash (after G. - * Knott) */ + disp = hSize - i; /* Secondary hash (after G. Knott) */ if (i == 0) { disp = 1; } probe: if ((i -= disp) < 0) { - i += hsize_reg; + i += hSize; } - if (state.htab[i] == fcode) { - ent = state.codetab[i]; + if (state.hashTable[i] == fcode) { + ent = state.codeTable[i]; continue; } - if ((long) state.htab[i] > 0) { + if ((long) state.hashTable[i] > 0) { goto probe; } nomatch: - output(&state, (long) ent); - state.out_count++; + Output(&state, (long) ent); + state.outCount++; 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; + if (U(state.freeEntry) < U((long)1 << GIFBITS)) { + state.codeTable[i] = state.freeEntry++; /* code -> hashtable */ + state.hashTable[i] = fcode; } else { - cl_block(&state); + ClearForBlock(&state); } } @@ -1943,91 +1998,87 @@ compress( * Put out the final code. */ - output(&state, (long)ent); - state.out_count++; - output(&state, (long) state.EOFCode); - - return; + Output(&state, (long) ent); + state.outCount++; + Output(&state, (long) state.eofCode); } /***************************************************************** - * TAG( output ) + * Output -- + * Output the given code. * - * Output the given code. * Inputs: - * code: A n_bits-bit integer. If == -1, then EOF. This assumes that - * n_bits =< (long) wordsize - 1. + * code: A numBits-bit integer. If == -1, then EOF. This assumes that + * numBits =< (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. + * 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( +Output( GIFState_t *statePtr, long code) { - statePtr->cur_accum &= masks[statePtr->cur_bits]; + static const unsigned long masks[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000F, + 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF + }; - if (statePtr->cur_bits > 0) { - statePtr->cur_accum |= ((long) code << statePtr->cur_bits); + statePtr->currentAccumulated &= masks[statePtr->currentBits]; + if (statePtr->currentBits > 0) { + statePtr->currentAccumulated |= ((long) code << statePtr->currentBits); } else { - statePtr->cur_accum = code; + statePtr->currentAccumulated = code; } + statePtr->currentBits += statePtr->numBits; - statePtr->cur_bits += statePtr->n_bits; - - while (statePtr->cur_bits >= 8 ) { - char_out(statePtr, (unsigned) (statePtr->cur_accum & 0xff)); - statePtr->cur_accum >>= 8; - statePtr->cur_bits -= 8; + while (statePtr->currentBits >= 8) { + CharOut(statePtr, (unsigned) (statePtr->currentAccumulated & 0xff)); + statePtr->currentAccumulated >>= 8; + statePtr->currentBits -= 8; } /* - * If the next entry is going to be too big for the code size, - * then increase it, if possible. + * 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; + if ((statePtr->freeEntry > statePtr->maxCode) || statePtr->clearFlag) { + if (statePtr->clearFlag) { + statePtr->maxCode = MAXCODE( + statePtr->numBits = statePtr->initialBits); + statePtr->clearFlag = 0; } else { - statePtr->n_bits++; - if (statePtr->n_bits == GIFBITS) { - statePtr->maxcode = (long)1 << GIFBITS; + statePtr->numBits++; + if (statePtr->numBits == GIFBITS) { + statePtr->maxCode = (long)1 << GIFBITS; } else { - statePtr->maxcode = MAXCODE(statePtr->n_bits); + statePtr->maxCode = MAXCODE(statePtr->numBits); } } } - if (code == statePtr->EOFCode) { + if (code == statePtr->eofCode) { /* * At EOF, write the rest of the buffer. */ - while (statePtr->cur_bits > 0) { - char_out(statePtr, (unsigned) (statePtr->cur_accum & 0xff)); - statePtr->cur_accum >>= 8; - statePtr->cur_bits -= 8; + while (statePtr->currentBits > 0) { + CharOut(statePtr, + (unsigned) (statePtr->currentAccumulated & 0xff)); + statePtr->currentAccumulated >>= 8; + statePtr->currentBits -= 8; } - flush_char(statePtr); + FlushChar(statePtr); } } @@ -2036,48 +2087,48 @@ output( */ static void -cl_block( /* table clear for block compress */ +ClearForBlock( /* Table clear for block compress. */ GIFState_t *statePtr) { - cl_hash(statePtr, (int) statePtr->hsize); - statePtr->free_ent = statePtr->ClearCode + 2; - statePtr->clear_flg = 1; + ClearHashTable(statePtr, (int) statePtr->hSize); + statePtr->freeEntry = statePtr->clearCode + 2; + statePtr->clearFlag = 1; - output(statePtr, (long) statePtr->ClearCode); + Output(statePtr, (long) statePtr->clearCode); } static void -cl_hash( /* reset code table */ +ClearHashTable( /* Reset code table. */ GIFState_t *statePtr, - int hsize) + int hSize) { - register int *htab_p = statePtr->htab + hsize; + register int *hashTablePtr = statePtr->hashTable + hSize; register long i; register long m1 = -1; - i = hsize - 16; + 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; + *(hashTablePtr-16) = m1; + *(hashTablePtr-15) = m1; + *(hashTablePtr-14) = m1; + *(hashTablePtr-13) = m1; + *(hashTablePtr-12) = m1; + *(hashTablePtr-11) = m1; + *(hashTablePtr-10) = m1; + *(hashTablePtr-9) = m1; + *(hashTablePtr-8) = m1; + *(hashTablePtr-7) = m1; + *(hashTablePtr-6) = m1; + *(hashTablePtr-5) = m1; + *(hashTablePtr-4) = m1; + *(hashTablePtr-3) = m1; + *(hashTablePtr-2) = m1; + *(hashTablePtr-1) = m1; + hashTablePtr -= 16; } while ((i -= 16) >= 0); for (i += 16; i > 0; i--) { - *--htab_p = m1; + *--hashTablePtr = m1; } } @@ -2094,12 +2145,12 @@ cl_hash( /* reset code table */ */ static void -char_init( +CharInit( GIFState_t *statePtr) { - statePtr->a_count = 0; - statePtr->cur_accum = 0; - statePtr->cur_bits = 0; + statePtr->accumulatedByteCount = 0; + statePtr->currentAccumulated = 0; + statePtr->currentBits = 0; } /* @@ -2108,13 +2159,13 @@ char_init( */ static void -char_out( +CharOut( GIFState_t *statePtr, int c) { - statePtr->accum[statePtr->a_count++] = c; - if (statePtr->a_count >= 254) { - flush_char(statePtr); + statePtr->packetAccumulator[statePtr->accumulatedByteCount++] = c; + if (statePtr->accumulatedByteCount >= 254) { + FlushChar(statePtr); } } @@ -2123,17 +2174,18 @@ char_out( */ static void -flush_char( +FlushChar( GIFState_t *statePtr) { unsigned char c; - if (statePtr->a_count > 0) { - c = statePtr->a_count; - Tcl_Write(statePtr->g_outfile, (const char *) &c, 1); - Tcl_Write(statePtr->g_outfile, (const char *) statePtr->accum, - statePtr->a_count); - statePtr->a_count = 0; + if (statePtr->accumulatedByteCount > 0) { + c = statePtr->accumulatedByteCount; + statePtr->writeProc(statePtr->destination, (const char *) &c, 1); + statePtr->writeProc(statePtr->destination, + (const char *) statePtr->packetAccumulator, + statePtr->accumulatedByteCount); + statePtr->accumulatedByteCount = 0; } } |