1 /*
2  * Copyright(c) 2012-2012, John Forkosh Associates, Inc. All rights reserved.
3  *           http://www.forkosh.com   mailto: john@forkosh.com
4  * Copyright (C) 2014 haru <uobikiemukot at gmail dot com>
5  * Copyright (C) 2014 Hayaki Saito <user@zuse.jp>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /* -------------------------------------------------------------------------
22 standard headers...
23 -------------------------------------------------------------------------- */
24 #include "config.h"
25 #include <stdio.h>
26 #include <stdint.h>
27 #include <stdlib.h>
28 #if HAVE_STRING_H
29 # include <string.h>
30 #endif
31 #if HAVE_CTYPE_H
32 # include <ctype.h>
33 #endif
34 #if defined(GSTESTDRIVE)
35   /* --- only needed for main() test driver below --- */
36 #include <math.h>
37 #endif
38 
39 #include "malloc_stub.h"
40 #include "gifsave89.h"
41 
42 /* -------------------------------------------------------------------------
43 additional gifsave89 parameters and macros...
44 -------------------------------------------------------------------------- */
45 /* ---
46  * bitfield macros (byte_bits=76543210, with lsb=bit#0 and 128=bit#7set)
47  * --------------------------------------------------------------------- */
48 #define getbit(x,bit)   ( ((x)>>(bit)) & 1 )        /* get   bit-th bit of x */
49 #define setbit(x,bit)   (  (x) |=  (1<<(bit)) )        /* set   bit-th bit of x */
50 #define clearbit(x,bit) (  (x) &= ~(1<<(bit)) )        /* clear bit-th bit of x */
51 #define putbit(x,bit,val) \
52             if(((int)(val))==0) clearbit((x),(bit)); else setbit((x),(bit))
53 #define        bitmask(nbits)        ((1<<(nbits))-1)        /* a mask of nbits 1's */
54 #define getbitfield(x,bit1,nbits) (((x)>>(bit1)) & (bitmask(nbits)))
55 #define        putbitfield(x,bit1,nbits,val)        /* x:bit1...bit1+nbits-1 = val */ \
56         if ( (nbits)>0 && (bit1)>=0 ) {        /* check input */ \
57           (x) &=      (~((bitmask((nbits))) << (bit1))); /*set field=0's*/ \
58           (x) |= (((val)&(bitmask((nbits)))) << (bit1)); /*set field=val*/ \
59           } /* let user supply final ; */
60 /* ---
61  * debugging, etc
62  * ----------------- */
63 /* --- debugging --- */
64 #define ismsgprint(gs,n) (gs==NULL?0:gs->msglevel>=(n)&&gs->msgfp!=NULL)
65 #define        OKAY ((status)>=0?1:0)        /*shortcut for funcs to check status */
66 static int msglevel =                        /* message level / verbosity */
67 #if defined(MSGLEVEL)                        /* if compiled with -DMSGLEVEL=n */
68         MSGLEVEL;                                        /*  use default msglevel=n */
69 #else                                                        /* otherwise */
70         0;                                                        /*  use 0 */
71 #endif
72 static char msgfile[132] = "\000";        /* file for msgs (stdout if "\0") */
73 #define        MSGFP stdout                        /* default msgfp */
74 /* --- etc --- */
75 #define        min2(x,y) ((x)<=(y)?(x):(y))        /* lesser of two values */
76 #define        max2(x,y) ((x)>=(y)?(x):(y))        /* larger of two values */
77 #define        absval(x) ((x)>=0?(x):(-(x)))        /* absolute value */
78 
79 /* -------------------------------------------------------------------------
80  * Comments and structs below provide detailed GIF89a format documentation
81  * -------------------------------------------------------------------------
82  * Structs for gif87a/89a block formats...
83  *       from: http://www.matthewflickinger.com/lab/whatsinagif/
84  *             http://www.fileformat.info/format/gif/egff.htm
85  *   also see: http://www.w3.org/Graphics/GIF/spec-gif89a.txt
86  * Several discrepancies between spec-gif89a.txt and egff.htm
87  * are "Note:"'ed below.
88  * If you prefer printed books, see Chapter 26 in
89  *   The File Formats Handbook, Gunter Born, ITP Publishing 1995,
90  *   ISBN 1-850-32128-0. From its publication date, you can see
91  *   it's old, but its gif format treatment remains unchanged.
92  * -------------------------------------------------------------------------
93  * gif file layout:
94  * Illustrated below is the basic gif file layout.
95  * o Each file begins with a Header and Logical Screen Descriptor.
96  *   An optional Global Color Table follows the Logical Screen Descriptor.
97  *   Each of these blocks is always found at the same offset in the file.
98  * o Each image stored in the file contains a Local Image Descriptor, an
99  *   optional Local Color Table, a single byte containing the LZW
100  *   minimum codesize, image data comprised of one or more sub-blocks,
101  *   followed by a terminating 0 byte.
102  * o The detailed byte-by-byte (and bit-by-bit where necessary) internal
103  *   structure for each type of block is laid out in the structs and
104  *   their accompanying comments below.
105  * o The last field in every gif file is a Terminator character (hex 3B).
106  * -------------------------------------------------------------------------
107  *                     +---
108  *  Header and Color   | Header
109  *  Table Information  | Logical Screen Descriptor
110  *                     | Global Color Table
111  *                     +---
112  *                     +---
113  *  Optional Extension | Comment Extension
114  *  information (valid | Application Extension
115  *  only for gif89a)   | Graphic Control Extension
116  *                     +---
117  *                      Either...
118  *                        +---
119  *  (gif89a only)         | Plain Text Extension
120  *                        +---
121  *                      Or...
122  *                        +---
123  *                        | Local Image Descriptor
124  *       Image 1          | Local Color Table
125  *                        | Image Data (preceded by LZW min codesize byte)
126  *                        +---
127  *                          ... optional extensions for ...
128  *                          ... Image 2, etc ...
129  *                     +---
130  *  Optional Extension | Comment Extension
131  *  information (valid | Application Extension
132  *  only for gif89a)   | Graphic Control Extension
133  *                     +---
134  *                      Either...
135  *                        +---
136  *  (gif89a only)         | Plain Text Extension
137  *                        +---
138  *                      Or...
139  *                        +---
140  *                        | Local Image Descriptor
141  *       Last Image       | Local Color Table
142  *                        | Image Data (preceded by LZW min codesize byte)
143  *                        +---
144  *                     +---
145  *  Trailer            | Trailer Byte (always hex 3B)
146  *                     +---
147  * -------------------------------------------------------------------------
148  * Notes:
149  *    o        WORD's are 16-bit (2-byte) integers, ordered little-endian,
150  *        regardless of cpu architecture byte ordering.
151  *    o        Image Data is preceded by a byte containing the minimum LZW codesize,
152  *        as stated above, and must also be followed by a byte containing 0
153  *        to terminate the sequence of sub-blocks.
154  *    o        gif89a added "Control Extensions" to gif87a, to control the
155  *        rendering of image data. 87a only allowed one image at a time
156  *        to be displayed in "slide show" fashion. Control Extensions allow
157  *        both textual and graphical data to be displayed, overlaid, and
158  *        deleted in "animated multimedia presentation" fashion.
159  *    o        Control Extension blocks may appear almost anywhere following the
160  *        Global Color Table. Extension blocks begin with the Extension
161  *        Introducer hex 21, followed by a Block Label (hex 00 to FF)
162  *        identifying the type of extension.
163  * -------------------------------------------------------------------------
164  * Flow diagram for assembling gif blocks...
165  * ------------------+------------------------------------------------------
166  * key: +----------+ |           +--------+
167  *      | required | |           | Header |
168  *      +----------+ |           +--------+
169  *                   |                |
170  *      +- - - - - + |  +---------------------------+
171  *      | optional | |  | Logical Screen Descriptor |
172  *      + - - - - -+ |  +---------------------------+
173  * ------------------+                |
174  *                          +- - - - - - - - - - +
175  *                          | Global Color Table |
176  *                          + - - - - - - - - - -+
177  *                                    |
178  *                                    |<--------------<------------------+
179  *                                    |                                  |
180  *                 +------------------+---------------+                  |
181  *                 |                                  |                  |
182  *                 |                         +- - - - - - - - -+         |
183  *                 |                         | Graphic Control |         ^
184  *                 |                         |    extension    |         |
185  *                 |                         + - - - - - - - - +         |
186  *                 |                                  |                  |
187  *                 |                         +--------+--------+         |
188  *                 |                         |                 |         ^
189  *                 |                         |          +------------+   |
190  *                 |                         |          |   Image    |   |
191  *                 |                         |          | Descriptor |   |
192  *         +-------+------+                  |          +------------+   |
193  *         |              |                  |                 |         ^
194  *  +-------------+ +-----------+     +------------+    +- - - - - - +   |
195  *  | Application | |  Comment  |     | Plain Text |    |    Local   |   |
196  *  |  extension  | | extension |     |  extension |    | Color Table|   |
197  *  +-------------+ +-----------+     +------------+    + - - - - - -+   |
198  *         |              |                  |                 |         ^
199  *         +-------+------+                  |             +-------+     |
200  *                 |                         |             | Image |     |
201  *                 |                         |             |  Data |     |
202  *                 |                         |             +-------+     |
203  *                 |                         |                 |         ^
204  *                 |                         +--------+--------+         |
205  *                 |                                  |                  |
206  *                 +---------------+------------------+                  |
207  *                                 |                                     |
208  *                                 +------------------>------------------+
209  *                                 |
210  *                            +---------+
211  *                            | Trailer |
212  *                            +---------+
213  * -------------------------------------------------------------------------
214  * PS:
215  *    o The structs defined below,
216  *          GIFHEADER, GIFCOLORTABLE, GIFIMAGEDESC,
217  *          GIFGRAPHICCONTROL, GIFPLAINTEXT, GIFAPPLICATION, GIFCOMMENT
218  *        aren't actually used by the gifsave89 (except for GIFAPPLICATION).
219  *        They're provided mostly to help document the gif file format.
220  *        But they're not actually used because structs can't typically
221  *        just be output as, e.g.,
222  *          memcpy((void *)image,(void *)&struct,sizeof(struct));
223  *        because we can't usually be sure structs are packed in memory.
224  *        Syntax for specifying packed structs to C compilers isn't
225  *        completely portably possible, so gifsave89 outputs each
226  *        member element separately.
227  * ----------------------------------------------------------------------- */
228 
229 /* ---
230  * Gif header and logical screen descriptor:
231  * -------------------------------------------- */
232 #define        GIFHEADER struct _GifHeader
233 GIFHEADER {
234         /* ---
235          * Header
236          * --------- */
237         BYTE Signature[3];                        /* Header Signature (always "GIF") */
238         BYTE Version[3];                        /* GIF format version ("87a" or "89a") */
239         /* ---
240          * Logical Screen Descriptor
241          * ---------------------------- */
242         WORD ScreenWidth;                        /* Width of Display Screen in Pixels */
243         WORD ScreenHeight;                        /* Height of Display Screen in Pixels */
244         /* ScreenHeight and Width are the minimum resolution to display
245            the image (if the display device does not support this resolution,
246            some sort of scaling is done to display the image). */
247         BYTE Packed;                                /* Screen and Color Map Information */
248         /* Packed contains four subfields, with bit 0 the
249            least significant bit, or LSB...
250            Bits 0-2: Size of each Global Color Table entry
251            the number of bits in each Global Color Table entry minus 1,
252            e.g., 7 if the image contains 8 bits per pixel. And the
253            number of Global Color Table entries is then
254            #GlobalColorTableEntries = 1 << (SizeOfTheGlobalColorTable + 1)
255            Bit    3: Global Color Table Sort Flag (always 0 for 87a)
256            if 1, then Global Color Table entries are sorted from the most
257            important (most frequently occurring) to the least (sorting
258            aids applications in choosing colors to use with displays that
259            have fewer colors than the image). Valid only for 89a, 0 for 87a.
260            Bits 4-6: Color Resolution
261            the number of bits in an entry of the original color palette
262            minus 1 (e.g., 7 if the image originally contained 8 bits per
263            primary color)
264            Bit    7: Global Color Table Flag
265            1 if a Global Color Table is present in the GIF file, and 0 if
266            not (if present, Global Color Table data always follows the
267            Logical Screen Descriptor header) */
268         BYTE BackgroundColor;                /* Background Color Index */
269         /* the Global Color Table index of the color to use for the image's
270            border and background */
271         BYTE AspectRatio;                        /* Pixel Aspect Ratio (usually 0) */
272         /* not used if 0, else the aspect ratio value of image pixels
273            (pixel width divided by the height, in the range of 1 to 255,
274            used as PixelAspectRatio = (AspectRatio+15)/64) */
275 };                                                                /* --- end-of-struct GIFHEADER --- */
276 
277 /* ---
278  * Gif color table:
279  * the number of entries in the Global Color Table is a power of two
280  * (2, 4, 8, 16, etc), up to 256. Its size in bytes is calculated using
281  * bits 0, 1, and 2 in the Packed field of the Logical Screen Descriptor:
282  * ColorTableSize(in bytes) = 3 * (1 << (SizeOfGlobalColorTable + 1))
283  * ----------------------------------------------------------------------- */
284 #define        GIFCOLORTABLE struct _GifColorTable
285 GIFCOLORTABLE {
286         BYTE Red;                                        /* Red Color Element */
287         BYTE Green;                                        /* Green Color Element */
288         BYTE Blue;                                        /* Blue Color Element */
289 };                                                                /* --- end-of-struct GIFCOLORTABLE --- */
290 
291 /* ---
292  * Gif local image descriptor:
293  * the Local Image Descriptor appears before each section of image data
294  * and has the following structure...
295  * ----------------------------------------------------------------------- */
296 #define GIFIMAGEDESC struct _GifImageDescriptor
297 GIFIMAGEDESC {
298         BYTE Separator;                                /* Image Descriptor identifier */
299         /* hex value 2C denoting the beginning of the Image Descriptor */
300         WORD Left;                                        /* X position of image on the display */
301         WORD Top;                                        /* Y position of image on the display */
302         /* Left, Top are pixel coords of the upper-left corner of the image
303            on the logical screen (the screen's upper-left corner is 0,0) */
304         WORD Width;                                        /* Width of the image in pixels */
305         WORD Height;                                /* Height of the image in pixels */
306         /* Width, Height are the image size in pixels */
307         BYTE Packed;                                /* Image and Color Table Data Information */
308         /* Packed contains five subfields, with bit 0 the LSB...
309            (Note/warning: egff.htm has this documented "backwards",
310            whereas spec-gif89a.txt is correct. The correct version is below.)
311            Bits 0-2: Size of each Local Color Table Entry
312            the number of bits in each Local Color Table entry minus 1
313            Bits 3-4: Reserved
314            Bit    5: Local Color Table Sort Flag (always 0 for 87a)
315            1 if entries in the Local Color Table are sorted in order of
316            importance, or 0 if unsorted (valid only for 89a, 0 for 87a)
317            Bit    6: Interlace Flag
318            1 if the image is interlaced, or 0 if it is non-interlaced
319            Bit    7: Local Color Table Flag
320            1 if a Local Color Table is present, or 0 to use
321            the Global Color Table */
322 };                                                                /* --- end-of-struct GIFIMAGEDESC --- */
323 
324 /* ---
325  * Gif graphics control extension block:
326  * A Graphics Control Extension block modifies how (either bitmap or text)
327  * data in the Graphics Rendering block that immediately follows it is
328  * displayed, e.g., whether the graphic is overlaid transparent or opaque
329  * over another graphic, whether it is to be restored or deleted, whether
330  * user input is expected before continuing with the display of data, etc.
331  * A Graphics Control block must occur before the data it modifies, and
332  * only one Graphics Control block may appear per Graphics Rendering block.
333  * ----------------------------------------------------------------------- */
334 #define GIFGRAPHICCONTROL struct _GifGraphicsControlExtension
335 GIFGRAPHICCONTROL {
336         BYTE Introducer;                        /* Extension Introducer (always hex 21) */
337         BYTE Label;                                        /* Graphic Control Label (always hex F9) */
338         BYTE BlockSize;                                /* Size of remaining fields (always hex 04) */
339         BYTE Packed;                                /* Method of graphics disposal to use */
340         /* Packed contains four subfields, with bit 0 the LSB...
341            Bit    0: Transparent Color Flag
342            if 1, the ColorIndex field contains a color transparency index
343            Bit    1: User Input Flag
344            if 1, user input (key press, mouse click, etc) is expected
345            before continuing to the next graphic sequence
346            Bits 2-4: Disposal Method
347            (Note: spec-gif89a.txt says values may be 0,1,2,3 rather
348            than 0,1,2,4 in egff.htm. 0,1,2,3 appears to be correct.)
349            Indicates how the graphic is to be disposed of after display...
350            hex 00 = disposal method not specified, hex 01 = do not dispose
351            of graphic, hex 02 = overwrite graphic with background color,
352            and hex 03 = restore with previous graphic
353            Bits 5-7: Reserved */
354         WORD DelayTime;                                /* Hundredths of seconds to wait */
355         /* hundredths of a second before graphics presentation continues,
356            or 0 for no delay */
357         BYTE ColorIndex;                        /* Transparent Color Index */
358         /* color transparency index (if the Transparent Color Flag is 1) */
359         BYTE Terminator;                        /* Block Terminator (always 0) */
360 };                                                                /* --- end-of-struct GIFGRAPHICCONTROL --- */
361 
362 /* ---
363  * Gif plain text extension block:
364  * Plain Text Extension blocks allow mixing ASCII text, displayed as
365  * graphics, with bitmapped image data, e.g., captions that are not
366  * part of the bitmapped image may be overlaid on it.
367  * ----------------------------------------------------------------------- */
368 #define GIFPLAINTEXT struct _GifPlainTextExtension
369 GIFPLAINTEXT {
370         BYTE Introducer;                        /* Extension Introducer (always hex 21) */
371         BYTE Label;                                        /* Extension Label (always hex 01) */
372         BYTE BlockSize;                                /* Size of Extension Block (always hex 0C) */
373         WORD TextGridLeft;                        /* X position of text grid in pixels */
374         WORD TextGridTop;                        /* Y position of text grid in pixels */
375         /* X,Y coords of the text grid with respect to the upper-left
376            corner of the display screen (0,0) */
377         WORD TextGridWidth;                        /* Width of the text grid in pixels */
378         WORD TextGridHeight;                /* Height of the text grid in pixels */
379         /* the size of the text grid in pixels */
380         BYTE CellWidth;                                /* Width of a grid cell in pixels */
381         BYTE CellHeight;                        /* Height of a grid cell in pixels */
382         /* the size in pixels of each character cell in the grid */
383         BYTE TextFgColorIndex;                /* Text foreground color index value */
384         BYTE TextBgColorIndex;                /* Text background color index value */
385         /* indexes into the (Global or Local) Color Table for the color
386            of the text, and for the color of the background */
387         BYTE *PlainTextData;                /* The Plain Text data */
388         /* the text to be rendered as a graphic, comprised of one or more
389            sub-blocks, each beginning with a byte containing the number of
390            text bytes (from 1 to 255) that follow */
391         BYTE Terminator;                        /* Block Terminator (always 0) */
392 };                                                                /* --- end-of-struct GIFPLAINTEXT --- */
393 
394 /* ---
395  * Gif application extension block:
396  * Application Extension blocks store data understood only by the application
397  * reading the gif file (similar to how tags are used in TIFF and TGA image
398  * file formats), e.g., instructions on changing video modes, on applying
399  * special processing to displayed image data, etc.
400  * ----------------------------------------------------------------------- */
401 #define GIFAPPLICATION struct _GifApplicationExtension
402 GIFAPPLICATION {
403         BYTE Introducer;                        /* Extension Introducer (always hex 21) */
404         BYTE Label;                                        /* Extension Label (always hex FF) */
405         BYTE BlockSize;                                /* Size of Extension Block (always hex 0B) */
406         BYTE Identifier[8];                        /* Application Identifier */
407         /* up to eight printable 7-bit ASCII chars, used to identify the
408            application that wrote the Application Extension block */
409         BYTE AuthentCode[3];                /* Application Authentication Code */
410         /* a value used to uniquely identify a software application that
411            created the Application Extension block, e.g., a serial number,
412            a version number, etc */
413         BYTE *ApplicationData;                /* Point to Application Data sub-blocks */
414         /* the data used by the software application, comprised of a series
415            of sub-blocks identical to data in Plain Text Extension blocks */
416         BYTE Terminator;                        /* Block Terminator (always 0) */
417 };                                                                /* --- end-of-struct GIFAPPLICATION --- */
418 
419 /* ---
420  * Gif comment extension block:
421  * data stored in Comment Extension blocks is to be read only by the user
422  * examining a gif file, and should be ignored by the application.
423  * ----------------------------------------------------------------------- */
424 #define GIFCOMMENT struct _GifCommentExtension
425 GIFCOMMENT {
426         BYTE Introducer;                        /* Extension Introducer (always hex 21) */
427         BYTE Label;                                        /* Comment Label (always hex FE) */
428         /*no BYTE BlockSize; *//* Size of Extension Block (always hex ??) */
429         BYTE *CommentData;                        /* Pointer to Comment Data sub-blocks */
430         /* one or more sub-blocks of ASCII string data (strings not
431            required to be NULL-terminated */
432         BYTE Terminator;                        /* Block Terminator (always 0) */
433 };                                                                /* --- end-of-struct GIFCOMMENT --- */
434 
435 
436 /* ==========================================================================
437  * Functions:        newgif(gifimage,width,height,colors,bgindex)
438  *                  animategif(gs,nrepetitions)                      *optional*
439  *                 plaintxtgif(gs,left,top,width,height,fg,bg,data)  *optional*
440  *                  controlgif(gs,tcolor,delay,userinput,disposal)   *optional*
441  *                putgif(gs,pixels) or                             *short form*
442  *                fputgif(gs,left,top,width,height,pixels,colors)   *long form*
443  *                endgif(gs)
444  *                --- alternative "short form" for a single gif image ---
445  *                makegif(nbytes,width,height,pixels,colors,bgindex)*short form*
446  * Purpose:        construct gif -- user-callable entry points for gifsave89
447  * --------------------------------------------------------------------------
448  * Arguments:
449  *        For newgif(), called once to intialize gif...
450  *                gifimage (O)        (void **) where ptr to buffer (that will
451  *                                be malloc'ed by gifsave89) containing
452  *                                constructed gif image is stored
453  *                width (I)        int containing screen (total image)
454  *                                width (#columns) in pixels
455  *                height (I)        int containing screen (total image)
456  *                                height (#rows) in pixels
457  *                colors (I)        int * to r,g,b, r,g,b, ..., -1 containing
458  *                                image colors for gif global color table
459  *                                (see putgifcolortable() comments for more
460  *                                details)
461  *                bgindex (I)        int containing colors[] index (0=first color)
462  *                                for background
463  *        For all subsequent function() calls...
464  *                gs (I)                void * returned by newgif() is always the
465  *                                first argument to every other function
466  *        For putgif(), called once or looped to render each frame of gif...
467  *                +------------------------------------------------------------
468  *                | Note: several variables removed as putgif() args; the more
469  *                | detailed entry point fputgif, below, includes top,left,
470  *                | width,height,colors args, to provide "full" functionality
471  *                | putgif() takes top,left of frame, relative to screen
472  *                | origin, as 0,0, and takes width,height as screen dimensions
473  *                +------------------------------------------------------------
474  *                gs (I)                as described above
475  *                pixels (I)        unsigned char * to width*height bytes,
476  *                                from upper-left to lower-right,
477  *                                each byte containing a colors[] index
478  *      For fputgif(), "full" putgif with additional args...
479  *                top, left (I)        ints containing row,col of upper-left
480  *                                corner pixel, with 0,0=upper-left of screen
481  *                width, height (I) ints containing width,height of pixels
482  *                                image (which must be less than width,height
483  *                                of screen if top,left>0,0)
484  *                colors (I)        int * to local color table for this frame,
485  *                                or NULL to use global color table
486  *        For endgif(), called once after all frames rendered...
487  *                gs (I)                as described above
488  *           For animategif(), optionally called once after newgif...
489  *                gs (I)                as described above
490  *                nrepetitions (I) int containing 0 to loop continuously,
491  *                                or containing #repetitions, 0 to 65535.
492  *           For plaintxtgif(), optionally called preceding put & control...
493  *                +------------------------------------------------------------
494  *                | Note: issues wget to mimeTeX to render image of plaintext
495  *                +------------------------------------------------------------
496  *           For controlgif(), optionally called immediately before putgif...
497  *                gs (I)                as described above
498  *                tcolor (I)        int containing colors[] index of
499  *                                transparent color, or -1 to not use
500  *                delay (I)        int containing delay in hundredths-of-second
501  *                                between frames, or 0 for no delay
502  *                userinput (I)        int containing 1 to wait for user keystroke
503  *                                or mouseclick before displaying next frame,
504  *                                or containing 0 if no user input required
505  *                disposal (I)        int containing disposition of frame after
506  *                                display
507  *                void (*gifimage=) *makegif(&nbytes_in_gifimage,
508  *                                          width,height,pixels,colors,bgindex)
509  * --------------------------------------------------------------------------
510  * Returns:        ( void * )        newgif() returns a ptr that must be passed
511  *                                as the first argument to every subsequent
512  *                                gifsave89 function called,
513  *                ( void * )        makegif() returns (unsigned char *)gifimage
514  *                                or both return NULL for any error.
515  *                ( int )                putgif() returns current #bytes in gifimage,
516  *                                endgif() returns total   #bytes in gifimage,
517  *                                all other functions (extension block funcs)
518  *                                return 1 if successful,
519  *                                and all return -1 for any error.
520  * --------------------------------------------------------------------------
521  * Notes:     o        sequence of gifsave function calls...
522  *                  First, call gs=newgif(&gifimage,etc) once.
523  *                  Next, optionally call animategif(gs,nrepetitions) once.
524  *                  Now, once or in a loop {
525  *                    optionally call controlgif(gs,etc)
526  *                    call putgif(gs,pixels) }
527  *                  Finally, call nbytes=endgif(gs) once.
528  *                  Do what you want with gifimage[nbytes], then free(gifimage)
529  *              o        minimal usage example/template
530  *                (see main() Notes for additional info)...
531  *                  void *gs=NULL, *newgif();
532  *                  int  nbytes=0, putgif(), endgif();
533  *                  int  width=255, height=255,
534  *                       *colors = { 255,255,255, 0,0,0, -1 },
535  *                       bgindex=0;
536  *                  unsigned char *pixels = { 0,1,0,1, ..., width*height };
537  *                  unsigned char *gifimage = NULL;
538  *                  gs = newgif(&gifimage,width,height,colors,bgindex);
539  *                  if ( gs != NULL ) {
540  *                    putgif(gs,pixels);
541  *                    nbytes = endgif(gs); }
542  *                  if ( nbytes > 0 ) {
543  *                    do_what_you_want_with(gifimage,nbytes);
544  *                    free(gifimage); }
545  * ======================================================================= */
546 /* ---
547  * entry point
548  * -------------- */
newgif(void ** gifimage,int width,int height,int * colors,int bgindex)549 void *newgif(void **gifimage, int width, int height,
550                          int *colors, int bgindex)
551 {
552 /* ---
553  * allocations and declarations
554  * ------------------------------- */
555         GS *newgifstruct(),                        /*allocate and init gif data struct */
556         *gs = newgifstruct((void **) gifimage, width, height);        /*new gif data */
557         int version = 89;                        /* default is GIF89a */
558         int putgifcolortable(),                /* emit (global) color table */
559          ncolorbits = putgifcolortable(NULL, colors);        /*#bits for color index */
560         BYTE Signature[4] = "GIF",        /* header always "GIF" */
561                 Version[4] = "89a";                /* and either 87a or 89a */
562         BYTE Packed = (BYTE) 0;                /* packed byte */
563         int AspectRatio = 0;                /* aspect ratio unused */
564         BK *bk = (gs == NULL ? NULL : &(gs->gifimage));        /* ptr to gif image block */
565         int putblkbytes(), putblkbyte(), putblkword();        /* write to image block */
566         int status = 1;                                /* init okay status */
567 /* ---
568  * check input
569  * -------------- */
570         if (gs == NULL)
571                 goto end_of_job;                /* failed to malloc gif data struct */
572         width = min2(9999, max2(1, width));        /* 1 <= width  <= 9999 */
573         height = min2(9999, max2(1, height));        /* 1 <= height <= 9999 */
574         gs->width = width;
575         gs->height = height;                /* reset values stored in gs */
576         bgindex = (max2(0, bgindex)) % 256;        /* 0<=bgindex<=255 */
577         gs->bgindex = bgindex;                /* global&local colortable bgindex */
578         gs->version = (version == 87 ? 87 : 89);        /* default to 89a if not 87 */
579         if (version == 87)
580                 memcpy(Version, "87a", 4);        /* reset to 87a if it is 87 */
581         if (!OKAY)
582                 goto end_of_job;                /* quit if input check failed */
583 /* ---
584  * header and screen descriptor
585  * ------------------------------- */
586         Packed = 0;                                        /* zero out Packed byte */
587         if (ncolorbits > 0) {                /* have colors[] color table */
588                 putbitfield(Packed, 0, 3, ncolorbits - 1);        /* #bits for color index - 1 */
589                 clearbit(Packed, 3);        /* clear color table sort flag bit */
590                 putbitfield(Packed, 4, 3, 8 - 1);        /* assume 8-bit color resolution */
591                 setbit(Packed, 7);                /* set global color table bit */
592         }
593 /* --- Header ---- */
594         status = putblkbytes(bk, Signature, 3);
595         if (OKAY)
596                 status = putblkbytes(bk, Version, 3);
597 /* --- Logical Screen Descriptor --- */
598         if (OKAY)
599                 status = putblkword(bk, width);
600         if (OKAY)
601                 status = putblkword(bk, height);
602         if (OKAY)
603                 status = putblkbyte(bk, Packed);
604         if (OKAY)
605                 status = putblkbyte(bk, bgindex);
606         if (OKAY)
607                 status = putblkbyte(bk, AspectRatio);
608         if (!OKAY)
609                 goto end_of_job;
610 /* ---
611  * global color table
612  * --------------------- */
613         gs->ncolorbits_gct =                /* store #colorbits in global table */
614                 gs->ncolorbits = max2(0, ncolorbits);        /* and default if no local table */
615         if (ncolorbits > 0) {                /* caller provided global colors[] */
616                 putgifcolortable(gs, colors);
617         }                                                        /* emit global color table */
618   end_of_job:
619         if (!OKAY)                                        /* something fouled up */
620                 if (gs != NULL) {                /* but we have an allocated gs */
621                         free((void *) gs);
622                         gs = NULL;
623                 }                                                /* free it and signal error */
624         return (((void *) gs));                /* return data struct as "blob" */
625 }                                                                /* --- end-of-function newgif() --- */
626 
627 /* ---
628  * entry point
629  * -------------- */
animategif(GS * gs,int nrepetitions,int delay,int tcolor,int disposal)630 int animategif(GS * gs, int nrepetitions,
631                            int delay, int tcolor, int disposal)
632 {
633 /* --- allocations and declarations --- */
634         int status = (-1);                        /* init for error */
635         int putgifapplication();        /* emit application extension */
636         GIFAPPLICATION gifapplication, *ga = (&gifapplication);
637         BK *bk = (gs == NULL ? NULL : &(gs->gifimage));        /* ptr to gif image block */
638         int putblkbytes(), putblkbyte(), putblkword();        /* write to image block */
639 /* ---
640  * check input
641  * -------------- */
642         if (bk == NULL)
643                 goto end_of_job;                /* no gif data struct supplied */
644         if (gs->version == 87)
645                 goto end_of_job;                /* no extensions for GIF87a */
646         if (gs->isanimated > 0)
647                 goto end_of_job;                /* just one animategif() per gif */
648         if (nrepetitions < 0 || nrepetitions > 65535)
649                 nrepetitions = 0;                /*0=continuous */
650 /* ---
651  * construct graphic control extension and emit it
652  * -------------------------------------------------- */
653         memset((void *) ga, 0, sizeof(GIFAPPLICATION));        /* zero out the whole thing */
654         memcpy(ga->Identifier, "NETSCAPE", 8);        /* netscape */
655         memcpy(ga->AuthentCode, "2.0", 3);        /* 2.0 */
656         ga->ApplicationData = NULL;        /* no data */
657         status = putgifapplication(gs, ga);        /* emit application extension hdr */
658 /* --- emit the data and terminator ourselves (for the time being) --- */
659         if (OKAY)
660                 status = putblkbyte(bk, 3);        /* 3 more bytes of data */
661         if (OKAY)
662                 status = putblkbyte(bk, 1);        /* data sub-block index (always 1) */
663         if (OKAY)
664                 status = putblkword(bk, nrepetitions);        /* #repetitions */
665         if (OKAY)
666                 status = putblkbyte(bk, 0);        /* sub-block sequence terminator */
667         if (OKAY) {
668                 gs->delay = delay;                /* set default frame delay */
669                 gs->tcolor = tcolor;        /* set default transparent index */
670                 gs->disposal = disposal;        /* set default disposal method */
671                 gs->isanimated++;
672         }                                                        /* set isanimated flag true */
673   end_of_job:
674         return (status);
675 }                                                                /* --- end-of-function animategif() --- */
676 
677 /* ---
678  * entry point
679  * -------------- */
plaintxtgif(GS * gs,int left,int top,int width,int height,int fg,int bg,char * data)680 int plaintxtgif(GS * gs, int left, int top, int width, int height,
681                                 int fg, int bg, char *data)
682 {
683 /* --- allocations and declarations --- */
684         int status = (-1);                        /* init signalling error */
685         int Introducer = 0x21;                /* always 0x21 */
686         int Label = 0x01;                        /* always 0x01 */
687         int BlockSize = 0x0C;                /* always 0x0C */
688         int Terminator = 0x00;                /* always 0x00 */
689         BK *bk = (gs == NULL ? NULL : &(gs->gifimage));        /* ptr to gif image block */
690         SB *sb = (gs == NULL ? NULL : &(gs->gifsubblock));        /* ptr to gif subblock */
691         int putblkbytes(), putblkbyte(), putblkword();        /* write to image block */
692         int putsubbytes(), flushsubblock();        /* data subblock */
693         int nchars = (data == NULL ? 0 : strlen(data));        /* #plaintext chars */
694         int cellwidth = 0, cellheight = height;        /* #pixels per char */
695         int ismimetex = 1;                        /* true to use mimetex for text */
696 /* ---
697  * check input
698  * -------------- */
699         if (bk == NULL || sb == NULL)
700                 goto end_of_job;                /*no gif data struct supplied */
701         if (gs->version == 87)
702                 goto end_of_job;                /* no extensions for GIF87a */
703         cellwidth = (nchars < 1 ? 0 : width / nchars);        /* #pixels/char width */
704         if (!ismimetex) {                        /* irrelevant args if using mimetex */
705                 if (cellwidth < 2 || height < 2)
706                         goto end_of_job;        /* won't work */
707                 if (nchars < 1)
708                         goto end_of_job;
709         }
710         /* no data won't work, either */
711         /* ---
712          * reset (turn off) any preceding "persistent" plaintext
713          * -------------------------------------------------------- */
714         if (ismimetex)                                /* but for mimeTeX... */
715                 if (nchars < 1) {                /* ...no data signals reset */
716                         gs->isplaintext = 0;        /* reset plaintext flag */
717                         if (gs->pt_pixels != NULL) {        /* have previous allocated image */
718                                 free(gs->pt_pixels);
719                                 gs->pt_pixels = NULL;
720                         }                                        /* free it and reset ptr */
721                         gs->pt_left = gs->pt_top = 0;        /* reset top-left corner col;row */
722                         gs->pt_bg = gs->pt_fg = 0;        /* reset bg,fg colortable indexes */
723                         gs->pt_width = gs->pt_height = 0;        /*reset pixelized text width,height */
724                         memset(gs->pt_data, 0, 1023);        /* reset text data */
725                         status = 1;                        /* set successful status */
726                         goto end_of_job;        /* plaintext reset */
727                 }
728         /* --- end-of-if(nchars<1) --- */
729         /* ---
730          * save mimetex data for subsequent putgif()
731          * -------------------------------------------- */
732         if (ismimetex) {                        /* use mimeTeX to render plaintext */
733                 gs->isplaintext = 1;        /* set plaintext flag */
734                 if (width < 0 || height < 0) {        /* set persistent text flag */
735                         gs->isplaintext = 2;        /* display same text on all frames */
736                         width = absval(width);
737                         height = absval(height);
738                 }                                                /* reset neg signal */
739                 gs->pt_left = left;
740                 gs->pt_top = top;                /* save top-left corner col;row */
741                 gs->pt_bg = bg;
742                 gs->pt_fg = fg;                        /* save bg,fg colortable indexes */
743                 gs->pt_width = gs->pt_height = 0;        /*reset pixelized text width,height */
744                 nchars = min2(1023, nchars);        /* don't overflow data[] buffer */
745                 strncpy(gs->pt_data, data, nchars);        /* local copy of text data */
746                 (gs->pt_data)[nchars] = '\000';        /* make sure it's null-terminated */
747                 if (gs->pt_pixels != NULL) {        /* have previous allocated image */
748                         free(gs->pt_pixels);
749                         gs->pt_pixels = NULL;
750                 }                                                /* free it and reset ptr */
751                 status = 1;                                /* set successful status */
752         }
753         /* --- end-of-if(ismimetex) --- */
754         /* ---
755          * or construct plain text extension and emit it
756          * ------------------------------------------------ */
757         if (!ismimetex) {                        /* emit gif89a plaintent extension */
758                 status = putblkbyte(bk, Introducer);
759                 if (OKAY)
760                         status = putblkbyte(bk, Label);
761                 if (OKAY)
762                         status = putblkbyte(bk, BlockSize);
763                 if (OKAY)
764                         status = putblkword(bk, left);
765                 if (OKAY)
766                         status = putblkword(bk, top);
767                 if (OKAY)
768                         status = putblkword(bk, width);
769                 if (OKAY)
770                         status = putblkword(bk, height);
771                 if (OKAY)
772                         status = putblkbyte(bk, cellwidth);
773                 if (OKAY)
774                         status = putblkbyte(bk, cellheight);
775                 if (OKAY)
776                         status = putblkbyte(bk, fg);
777                 if (OKAY)
778                         status = putblkbyte(bk, bg);
779                 if (OKAY)
780                         status = putsubbytes(sb, (BYTE *) data, nchars);
781                 if (OKAY)
782                         status = flushsubblock(sb);
783                 if (OKAY)
784                         status = putblkbyte(bk, Terminator);
785         }                                                        /* --- end-of-if(!ismimetex) --- */
786   end_of_job:
787         return (status);
788 }                                                                /* --- end-of-function plaintxtgif() --- */
789 
790 /* ---
791  * entry point
792  * -------------- */
controlgif(GS * gs,int tcolor,int delay,int userinput,int disposal)793 int controlgif(GS * gs, int tcolor, int delay, int userinput, int disposal)
794 {
795 /* --- allocations and declarations --- */
796         int status = (-1);                        /* init signalling error */
797         int Introducer = 0x21;                /* always 0x21 */
798         int Label = 0xF9;                        /* always 0xF9 */
799         int BlockSize = 0x04;                /* always 0x04 */
800         int Terminator = 0x00;                /* always 0x00 */
801         BYTE Packed = (BYTE) 0;                /* packed byte */
802         BK *bk = (gs == NULL ? NULL : &(gs->gifimage));        /* ptr to gif image block */
803         int putblkbytes(), putblkbyte(), putblkword();        /* write to image block */
804 /* ---
805  * check input
806  * -------------- */
807         if (bk == NULL)
808                 goto end_of_job;                /* no gif data struct supplied */
809         if (gs->version == 87)
810                 goto end_of_job;                /* no extensions for GIF87a */
811         if (gs->ncontrol > 0)
812                 goto end_of_job;                /* just one control per image */
813         if (tcolor < 0 || tcolor > 255)
814                 tcolor = (-1);                        /* not transparent if illegal */
815         if (delay < 0 || delay > 65535)
816                 delay = 0;                                /* 0 if illegal (<0 or >2**16-1) */
817         userinput = (userinput <= 0 ? 0 : 1);        /* "yes" if positive */
818         if (disposal != 1 && disposal != 2        /* 0,1,2,3 are okay */
819                 && disposal != 3)
820                 disposal = 0;                        /* default to 0 otherwise */
821 /* ---
822  * construct graphic control extension and emit it
823  * -------------------------------------------------- */
824         putbit(Packed, 0, (tcolor >= 0 ? 1 : 0));        /* set transparent color flag */
825         putbit(Packed, 1, userinput);        /* set user input flag */
826         putbitfield(Packed, 2, 3, disposal);        /* set requested disposal method */
827         putbitfield(Packed, 5, 3, 0);        /* clear reserved bits */
828         status = putblkbyte(bk, Introducer);
829         if (OKAY)
830                 status = putblkbyte(bk, Label);
831         if (OKAY)
832                 status = putblkbyte(bk, BlockSize);
833         if (OKAY)
834                 status = putblkbyte(bk, Packed);
835         if (OKAY)
836                 status = putblkword(bk, delay);
837         if (OKAY)
838                 status = putblkbyte(bk, (tcolor < 0 ? 0 : tcolor));
839         if (OKAY)
840                 status = putblkbyte(bk, Terminator);
841         if (OKAY)
842                 gs->ncontrol++;                        /* count (another?) graphic control */
843   end_of_job:
844         return (status);
845 }                                                                /* --- end-of-function controlgif() --- */
846 
847 /* ---
848  * entry point
849  * -------------- */
putgif(GS * gs,void * pixels)850 int putgif(GS * gs, void *pixels)
851 {
852 /* --- allocations and declarations --- */
853         int status = (-1), fputgif();        /* fputgif() does all the work */
854 /* --- call fputgif() --- */
855         if (gs != NULL && pixels != NULL)        /* caller passed required args */
856                 status = fputgif(gs, 0, 0, gs->width, gs->height, pixels, NULL);
857         return (status);                        /* return current #bytes in image */
858 }                                                                /* --- end-of-function putgif() --- */
859 
860 /* ---
861  * entry point
862  * -------------- */
fputgif(GS * gs,int left,int top,int width,int height,void * pixels,int * colors)863 int fputgif(GS * gs, int left, int top, int width, int height,
864                         void *pixels, int *colors)
865 {
866 /* --- allocations and declarations --- */
867 #if 0
868         int width = (gs == NULL ? 0 : gs->width),        /* default  width: image = screen */
869                 height = (gs == NULL ? 0 : gs->height);        /* default height: image = screen */
870         int left = 0, top = 0;                /* default left,top coords */
871 #endif
872         int Separator = 0x2C;                /* image descrip separator is 0x2C */
873         BYTE Packed = (BYTE) 0;                /* packed byte */
874         BK *bk = (gs == NULL ? NULL : &(gs->gifimage));        /* ptr to gif image block */
875         int npixels = (gs == NULL ? (-1) : gs->npixels);        /* width*height */
876         int putblkbytes(), putblkbyte(), putblkword();        /* write to image block */
877         int codesize;                                /* write min lzw codesize byte */
878         int nbytes = 0, encodelzw();        /* lzw encode the image pixels */
879         int putgifcolortable(),                /* emit (local) color table */
880          ncolorbits = putgifcolortable(NULL, colors);        /*#bits for color index */
881         BYTE *plainmimetext(),                /* pixelize plaintext data, */
882         *overpix = NULL, *overlay();        /* and overlay that text on pixels */
883         int controlgif();                        /* to emit animation controlgif() */
884         int isextensionallowedbetween = 0;        /* true for descrip+extension+image */
885         int fprintpixels();                        /* user-requested debug display */
886         int status = (-1);                        /* init for error */
887 /* ---
888  * check input
889  * ----------- */
890         if (bk == NULL)
891                 goto end_of_job;                /* no gs data provided */
892         if (!isextensionallowedbetween)        /*allow extension between descrip/image? */
893                 if (pixels == NULL || width < 1 || height < 1)        /* if not allowed, then */
894                         goto end_of_job;        /*signal error for any missing args */
895 /* --- debug pixel display --- */
896         if (ismsgprint(gs, 32))                /* msglevel >= 32 */
897                 fprintpixels(gs, (gs->msglevel >= 99 ? 2 : 1), pixels);        /* hex format if >=99 */
898 /* ---
899  * emit default controlgif() for animations if not already done by user
900  * ----------------------------------------------------------------------- */
901         if (gs->isanimated > 0)                /* rendering gif animation */
902                 if (gs->ncontrol < 1) {        /* but no graphic control for frame */
903                         status = controlgif(gs,        /* default graphic control... */
904                                                                 gs->tcolor,        /* default animation transparency */
905                                                                 gs->delay,        /* default animation frame delay */
906                                                                 0,        /* userinput always 0 */
907                                                                 gs->disposal);        /* default animation disposal */
908                         if (!OKAY)
909                                 goto end_of_job;        /* quit if failed */
910                         gs->ncontrol++;
911                 }
912         /* count controlgif() call */
913         /* ---
914          * image descriptor
915          * ------------------- */
916         if (width >= 1 && height >= 1) {
917                 gs->npixels = npixels = width * height;        /* set for encodelzw() */
918                 Packed = (BYTE) 0;                /* zero out Packed byte */
919                 putbit(Packed, 7, max2(0, ncolorbits));        /* set local color table bit */
920                 clearbit(Packed, 6);        /* clear interlace flag bit */
921                 clearbit(Packed, 5);        /* clear sort flag bit */
922                 putbitfield(Packed, 3, 2, 0);        /* clear reserved bits */
923                 if (ncolorbits > 0) {        /* have colors[] color table */
924                         putbitfield(Packed, 0, 3, ncolorbits - 1);
925                 }                                                /* #bits for color index - 1 */
926                 status = putblkbyte(bk, Separator);
927                 if (OKAY)
928                         status = putblkword(bk, left);
929                 if (OKAY)
930                         status = putblkword(bk, top);
931                 if (OKAY)
932                         status = putblkword(bk, width);
933                 if (OKAY)
934                         status = putblkword(bk, height);
935                 if (OKAY)
936                         status = putblkbyte(bk, Packed);
937                 if (!OKAY)
938                         goto end_of_job;
939                 /* ---
940                  * local color table
941                  * -------------------- */
942                 if (ncolorbits > 0) {        /* caller provided local colors[] */
943                         putgifcolortable(gs, colors);        /* emit local color table */
944                         gs->ncolorbits = ncolorbits;
945                 } /* and set #bits for local table */
946                 else
947                         gs->ncolorbits = gs->ncolorbits_gct;        /*else default to global table */
948         }
949         /* end-of-if(width>1&&height>1) --- */
950         /* ---
951          * lzw-encode the pixels
952          * ------------------------ */
953         if (pixels != NULL && npixels > 0) {        /* have pixels to be encoded */
954                 /* ---
955                  * first overlay plaintext, if present
956                  * ------------------------------------- */
957                 if (gs->isplaintext > 0) {        /* have plaintext data */
958                         if (gs->pt_pixels == NULL)        /* but need new pixel image */
959                                 gs->pt_pixels =
960                                         plainmimetext(gs->pt_data, &gs->pt_width,
961                                                                   &gs->pt_height);
962                         if (gs->pt_pixels != NULL)        /* got new image or still have old */
963                                 overpix = overlay(pixels, gs->width, gs->height,        /* so overlay it */
964                                                                   gs->pt_pixels, gs->pt_width,
965                                                                   gs->pt_height, gs->pt_left, gs->pt_top,
966                                                                   gs->pt_bg, gs->pt_fg);
967                         if (overpix != NULL)        /*got text pixels overlaid on image */
968                                 pixels = overpix;        /* so that's what we want to see */
969                 }
970                 /* --- end-of-if(gs->isplaintext>0) --- */
971                 /* ---
972                  * LZW minimum codesize byte
973                  * ------------------------- */
974                 codesize = max2(2, (gs->ncolorbits /*-1*/ ));        /*local/global table, but >=2 */
975                 status = putblkbyte(bk, codesize);        /* emit min codesize byte */
976                 if (!OKAY)
977                         goto end_of_job;        /* quit if failed */
978                 /* ---
979                  * lzw encode the image
980                  * ----------------------- */
981                 nbytes = encodelzw(gs, codesize, npixels, (BYTE *) pixels);        /* encode pixels */
982                 status = (nbytes < 1 ? (-1) : putblkbyte(bk, 0));        /* 0 terminates sub-blocks */
983                 /* ---
984                  * reset for next image
985                  * ----------------------- */
986                 gs->npixels = (-1);                /* new image descrip for next image */
987                 gs->ncontrol = 0;                /* no controlgif() calls issued yet */
988                 /* --- reset (plain)text overlay --- */
989                 if (overpix != NULL)
990                         free((void *) overpix);        /*free text overlay pixels */
991                 if (gs->isplaintext == 1) {        /*plaintext was for this frame only */
992                         if (gs->pt_pixels != NULL) {        /*should have allocated pixel image */
993                                 free((void *) (gs->pt_pixels));        /* ...free it */
994                                 gs->pt_pixels = NULL;
995                         }                                        /* ...and reset its ptr */
996                         gs->isplaintext = 0;
997                 }                                                /* always reset plaintext flag */
998         }                                                        /* --- end-of-if(pixels!=NULL&&npixels>0) --- */
999   end_of_job:
1000         return ((OKAY ? bk->nblkbytes : status));        /* return current #bytes in image */
1001 }                                                                /* --- end-of-function fputgif() --- */
1002 
1003 /* ---
1004  * entry point
1005  * -------------- */
endgif(GS * gs)1006 int endgif(GS * gs)
1007 {
1008         BK *bk = (gs == NULL ? NULL : &(gs->gifimage));        /* ptr to gif image block */
1009         SB *sb = (gs == NULL ? NULL : &(gs->gifsubblock));        /* ptr to gif subblock */
1010         int nblkbytes = (-1);                /* init for error */
1011         int status = (-1), flushsubblock(), putblkbyte();        /* final write */
1012         int Trailer = 0x3B;                        /* gif trailer byte */
1013         if (bk != NULL) {                        /* have buffers */
1014                 status = flushsubblock(sb);        /* flush anything remaining */
1015                 if (OKAY)
1016                         status = putblkbyte(bk, Trailer);        /* write 0x3B trailer byte */
1017                 if (OKAY)
1018                         nblkbytes = bk->nblkbytes;
1019         }                                                        /*return tot #bytes in gifimage */
1020         if (gs != NULL) {                        /* have gs */
1021                 if (gs->pt_pixels != NULL)        /* have allocated text pixel image */
1022                         free((void *) (gs->pt_pixels));        /* so free it */
1023                 if (gs->msgfp != NULL && gs->msgfp != stdout) {        /* have open message file */
1024                         fclose(gs->msgfp);        /* so close it */
1025                         *msgfile = '\000';        /* and reset message file */
1026                         msglevel = 0;
1027                 }                                                /* and message level */
1028                 free((void *) gs);
1029         }
1030         return (nblkbytes);                        /* return total #bytes or -1=error */
1031 }                                                                /* --- end-of-function endgif() --- */
1032 
1033 /* ---
1034  * entry point
1035  * -------------- */
makegif(int * nbytes,int width,int height,void * pixels,int * colors,int bgindex)1036 void *makegif(int *nbytes, int width, int height, void *pixels,
1037                           int *colors, int bgindex)
1038 {
1039 /* --- allocations and declarations --- */
1040         void *gs = NULL, *newgif(),        /* gifsave89 data structure */
1041                 *gifimage = NULL;                /* constructed gif back to caller */
1042         int ngifbytes = 0, putgif(), endgif();        /* add pixel image to gif */
1043         int tcolor = (bgindex < 0 ? -bgindex : -1);        /* optional transparent color */
1044 /* --- check input --- */
1045         if (width < 1 || height < 1 || pixels == NULL        /* quit if no image */
1046                 || colors == NULL)
1047                 goto end_of_job;                /* or no colors */
1048         bgindex = absval(bgindex);        /* make sure it's positive (or 0) */
1049 /* --- construct the gif --- */
1050         if ((gs = newgif(&gifimage, width, height, colors, bgindex))        /* init gsave89 */
1051                 !=NULL) {                                /* check if init succeeded */
1052                 if (tcolor >= 0)                /*transparent color index requested */
1053                         controlgif(gs, tcolor, 0, 0, 0);        /* set requested tcolor index */
1054                 putgif(gs, pixels);                /* encode pixel image */
1055                 ngifbytes = endgif(gs);
1056         } /* all done */
1057         else {                                                /*newgif() failed to init gifsave89 */
1058                 if (gifimage != NULL)
1059                         free(gifimage);                /* free gifimage if malloc'ed */
1060                 gifimage = NULL;
1061         }                                                        /* reset returned ptr */
1062   end_of_job:
1063         if (nbytes != NULL)                        /* return #bytes in gifimage */
1064                 *nbytes = (gifimage == NULL ? 0 : ngifbytes);        /* or 0 for error */
1065         return (gifimage);                        /* back to caller with gif */
1066 }                                                                /* --- end-of-function makegif() --- */
1067 
1068 
1069 /* ==========================================================================
1070  * Functions:        newgifstruct ( void **gifimage, int width, int height )
1071  *                debuggif ( int dblevel, char *dbfile )
1072  * Purpose:        gif helper functions,
1073  *                  newgifstruct allocates and inits a GS structure
1074  *                  debuggif sets static msglevel and msgfile
1075  * --------------------------------------------------------------------------
1076  * Arguments:        --- newgifstruct ---
1077  *                gifimage (I)        (void **) to user's buffer for image
1078  *                width (I)        int containing #col pixels for screen
1079  *                height (I)        int containing #row pixels for screen
1080  *                --- debuggif ---
1081  *                dblevel (I)        int containing new static msglevel
1082  *                dbfile (I)        (char ) containing null-terminated string
1083  *                                with full path/name of new static msgfile
1084  * --------------------------------------------------------------------------
1085  * Returns:        ( GS * )        newgifstruct returns a ptr to a malloc()'ed
1086  *                                and initialized GS struct whose .gifimage BK
1087  *                                contains the caller's **gifimage,
1088  *                                or NULL for any error.
1089  *                ( int )                debuggif returns 1
1090  * --------------------------------------------------------------------------
1091  * Notes:     o
1092  * ======================================================================= */
1093 /* ---
1094  * entry point
1095  * -------------- */
newgifstruct(void ** gifimage,int width,int height)1096 GS *newgifstruct(void **gifimage, int width, int height)
1097 {
1098         GS *gs = (gifimage == NULL ? NULL : (GS *) malloc(sizeof(GS)));
1099         if (gs == NULL)
1100                 goto end_of_job;                /* failed to allocate memory */
1101         memset((void *) gs, 0, sizeof(GS));        /* zero out entire struct */
1102 /* ---
1103  * debugging
1104  * ------------ */
1105         gs->msglevel = msglevel;        /* desired verbosity */
1106         gs->msgfp = MSGFP;                        /* debug file ptr (default) */
1107         if (msglevel > 1 && *msgfile != '\000')        /* redirect debug output to file */
1108                 if ((gs->msgfp = fopen(msgfile, "a"))        /* append debug msgs to file */
1109                         == NULL)
1110                         gs->msgfp = MSGFP;        /* back to default if fopen fails */
1111         if (ismsgprint(gs, 1))                /* messages enabled? */
1112                 fprintf(gs->msgfp, "%s\n", copyright);        /* always display gnu/gpl copyright */
1113 /* ---
1114  * gifimage block buffer
1115  * ------------------------ */
1116         gs->gifimage.block = (BYTE **) gifimage;        /*user's buffer for returned image */
1117         *(gs->gifimage.block) = (BYTE *) NULL;        /* nothing allocated yet */
1118         gs->gifimage.maxblkbytes = 0;        /* #bytes currently allocated */
1119         gs->gifimage.nblkbytes = 0;        /* #bytes currently in gifimage */
1120 /* ---
1121  * subblock buffer
1122  * ----------------- */
1123         gs->gifsubblock.block = &(gs->gifimage);        /* ptr back to parent block */
1124         gs->gifsubblock.nsubbytes = 0;        /* #bytes already in gif subblock */
1125         gs->gifsubblock.nsubbits = 0;        /* #bits already in current byte */
1126         gs->gifsubblock.index = (-1);        /* index# **not** wanted */
1127 /* ---
1128  * LZW string table
1129  * ------------------- */
1130         gs->nstrings = 0;                        /* #strings in lzw string table */
1131 /* ---
1132  * additional control data
1133  * -------------------------- */
1134         gs->width = max2(0, min2(9999, width));        /* #cols for screen in pixels */
1135         gs->height = max2(0, min2(9999, height));        /* #rows for screen in pixels */
1136         gs->ncolorbits_gct = gs->ncolorbits = 0;        /* no color table(s) yet */
1137         gs->bgindex = 0;                        /* no colortable bgindex yet */
1138         gs->npixels = (-1);                        /* no image descriptor yet */
1139         gs->ncontrol = 0;                        /* no controlgif() calls issued yet */
1140         gs->isanimated = 0;                        /* set true if animategif() called */
1141         gs->delay = 0;                                /* default animation frame delay */
1142         gs->tcolor = (-1);                        /*  " animation transparency index */
1143         gs->disposal = 2;                        /*  " animation disposal method */
1144 /* ---
1145  * plaintext control data
1146  * ------------------------- */
1147         gs->isplaintext = 0;                /* plaintext flag, 1 if present */
1148         gs->pt_left = gs->pt_top = 0;        /* top-left corner col;row */
1149         gs->pt_bg = gs->pt_fg = 0;        /* bg,fg colortable indexes */
1150         gs->pt_width = gs->pt_height = 0;        /* bg,fg colortable indexes */
1151         memset(gs->pt_data, 0, 1024);        /* local copy of user text data */
1152         gs->pt_pixels = NULL;                /* no pixels allocated */
1153   end_of_job:
1154         return (gs);                                /* new struct or NULL for error */
1155 }                                                                /* --- end-of-function newgifstruct() --- */
1156 
1157 /* ---
1158  * entry point
1159  * -------------- */
debuggif(int dblevel,char * dbfile)1160 int debuggif(int dblevel, char *dbfile)
1161 {
1162         msglevel = max2(0, min2(999, dblevel));        /* 0<=msglevel<=999 */
1163         *msgfile = '\000';                        /* reset msgfile */
1164         if (dbfile != NULL)                        /* have dbfile arg */
1165                 if (*dbfile != '\000') {        /* that's not an empty string */
1166                         strncpy(msgfile, dbfile, 127);        /* set msgfile (max 127 chars) */
1167                         msgfile[127] = '\000';
1168                 }                                                /* make sure it's null-terminated */
1169         return (1);
1170 }                                                                /* --- end-of-function debuggif() --- */
1171 
1172 /* ---
1173  * entry point
1174  * -------------- */
fprintpixels(GS * gs,int format,void * pixels)1175 int fprintpixels(GS * gs, int format, void *pixels)
1176 {
1177 /* -------------------------------------------------------------------------
1178 Allocations and Declarations
1179 -------------------------------------------------------------------------- */
1180         static int display_width = 72;        /* max columns for display */
1181         char scanline[999];                        /* ascii image for one scan line */
1182         char fgchar = '*', bgchar = '.';        /* foreground/background chars */
1183         static char *hexchars = "0123456789ABCDEFxxxxxxxxxx";        /* for hex display */
1184         int scan_width = 0;                        /* #chars in scan (<=display_width) */
1185         int irow = 0, locol = 0, hicol = (-1);        /* height index, width indexes */
1186         FILE *fp = gs->msgfp;                /* pointer to output device */
1187 /* --------------------------------------------------------------------------
1188 initialization
1189 -------------------------------------------------------------------------- */
1190 /* --- redirect null fp --- */
1191         if (fp == NULL)
1192                 fp = MSGFP;                                /* default fp if null */
1193 /* --- adjust display for hexdump --- */
1194         if (format != 1)
1195                 display_width /= 3;                /* "xx xx xx..." for hex display */
1196 /* --- header line --- */
1197         fprintf(fp, "fprintpixels> width=%d height=%d ...\n", gs->width,
1198                         gs->height);
1199 /* --------------------------------------------------------------------------
1200 display ascii dump of image raster (in segments if display_width < gr->width)
1201 -------------------------------------------------------------------------- */
1202         while ((locol = hicol + 1) < gs->width) {        /*start where prev segment left off */
1203                 /* --- set hicol for this pass (locol set above) --- */
1204                 hicol += display_width;        /* show as much as display allows */
1205                 if (hicol >= gs->width)
1206                         hicol = gs->width - 1;        /*but not more than pixels */
1207                 scan_width = hicol - locol + 1;        /* #chars in this scan */
1208                 if (locol > 0)
1209                         fprintf(fp, "----------\n");        /*separator between segments */
1210                 /* ------------------------------------------------------------------------
1211                    display all scan lines for this local...hicol segment range
1212                    ------------------------------------------------------------------------ */
1213                 for (irow = 0; irow < gs->height; irow++) {        /* all scan lines for col range */
1214                         /* --- allocations and declarations --- */
1215                         int lopix = irow * gs->width + locol;        /* index of 1st pixel in this scan */
1216                         int ipix;                        /* pixel index for this scan */
1217                         /* --- set chars in scanline[] based on pixels --- */
1218                         memset(scanline, ' ', 255);        /* blank out scanline */
1219                         for (ipix = 0; ipix < scan_width; ipix++) {        /* set each char or hexbyte */
1220                                 int pixel = (int) (((BYTE *) pixels)[lopix + ipix]);        /* current pixel */
1221                                 int isbg = (pixel == gs->bgindex ? 1 : 0);        /* background pixel */
1222                                 if (format == 1)
1223                                         scanline[ipix] = (isbg ? bgchar : fgchar);
1224                                 else {                        /* dump hex byte */
1225                                         int icol = 3 * ipix;        /* first col for display */
1226                                         if (isbg)
1227                                                 scanline[icol] = scanline[icol + 1] = bgchar;
1228                                         else {
1229                                                 scanline[icol] = hexchars[(pixel / 16) % 16];
1230                                                 scanline[icol + 1] = hexchars[pixel % 16];
1231                                         }
1232                                 }                                /* --- end-of-if/else(format==1) --- */
1233                         }                                        /* --- end-of-for(ipix) --- */
1234                         /* --- display completed scan line --- */
1235                         fprintf(fp, "%.*s\n", scan_width * (format == 1 ? 1 : 3),
1236                                         scanline);
1237                 }                                                /* --- end-of-for(irow) --- */
1238         }                                                        /* --- end-of-while(hicol<gs->width) --- */
1239 /* -------------------------------------------------------------------------
1240 Back to caller with 1=okay, 0=failed.
1241 -------------------------------------------------------------------------- */
1242         return (1);
1243 }                                                                /* --- end-of-function fprintpixels() --- */
1244 
1245 
1246 /* ==========================================================================
1247  * Function:        plainmimetext ( char *expression, int *width, int *height )
1248  * Purpose:        obtain pixel image corresponding to expression
1249  *                by "calling" mimetex, using wget,
1250  *                for pbm-style bitmap of expression,
1251  *                and then pixelizing it.
1252  * --------------------------------------------------------------------------
1253  * Arguments:        expression (I)        char * to null-terminated string
1254  *                                containing any TeX expression
1255  *                                recognized by mimeTeX
1256  *                                See http://www.forkosh.com/mimetex.html
1257  *                width, height (O)  int * pointers returning
1258  *                                width,height of generated pixelized image
1259  * --------------------------------------------------------------------------
1260  * Returns:        ( BYTE * )        newly allocated pixel array with pixelized
1261  *                                image of input expression, rendered
1262  *                                by mimetex, or NULL for any error.
1263  * --------------------------------------------------------------------------
1264  * Notes:     o        Caller must free(returned_pixels) when finished with them.
1265  * ======================================================================= */
1266 /* ---
1267  * entry point
1268  * -------------- */
plainmimetext(char * expression,int * width,int * height)1269 BYTE *plainmimetext(char *expression, int *width, int *height)
1270 {
1271 /* ---
1272  * allocations and declarations
1273  * ------------------------------- */
1274         BYTE *pixels = NULL;                /* returned pixels */
1275         char command[2048],                        /* complete popen(command,"r")... */
1276         *execwget = WGET                        /*...begins with /path/to/wget */
1277                 " -q -O - "                                /*...followed by wget options */
1278                 "\"" MIMETEX "?\\pbmpgm{1} ";        /*..."mimetex.cgi?\pbmpgm{1}... */
1279         FILE *wget = NULL;                        /* wget's stdout */
1280         char pipeline[512],                        /* fgets(pipeline,511,wget) buffer */
1281         *pipeptr = NULL, *endptr = NULL;        /* strtol ptr to 1st char after num */
1282         char *magicnumber = "P1";        /* filetype identification */
1283         int gotmagic = 0;                        /* set true when magicnumber found */
1284         int ncols = 0, nrows = 0,        /* local width,height from wget */
1285                 ipixel = 0, npixels = 0,        /* and index, npixels=ncols*nrows */
1286                 pixval = 0;                                /* pixval=strtol() from pipeline */
1287 /* ---
1288  * initialization
1289  * ----------------- */
1290 /* --- check arguments --- */
1291         if (width != NULL)
1292                 *width = 0;                                /* init for error */
1293         if (height != NULL)
1294                 *height = 0;                        /* init for error */
1295         if (expression == NULL)
1296                 goto end_of_job;                /* nothing to pixelize */
1297         if (*expression == '\000')
1298                 goto end_of_job;                /* still nothing to pixelize */
1299         if (strlen(expression) > 1536)
1300                 goto end_of_job;                /*too much (sanity check) */
1301 /* ---
1302  * open pipe to wget
1303  * -------------------- */
1304 /* --- first construct popen() command --- */
1305         strcpy(command, execwget);        /* shell command plus mimetex url */
1306         strcat(command, expression);        /* followed by caller's expression */
1307         strcat(command, "\"");                /* and closing " */
1308 /* --- issue wget command and capture its stdout --- */
1309         if ((wget = popen(command, "r"))        /* issue command and capture stdout */
1310                 == NULL)
1311                 goto end_of_job;                /* or quit if failed */
1312 /* ---
1313  * read the first few lines to get width, height
1314  * ------------------------------------------------ */
1315         while (1) {                                        /* read lines (shouldn't find eof) */
1316                 if (fgets(pipeline, 511, wget) == NULL)
1317                         goto end_of_job;        /*premature eof */
1318                 if (gotmagic) {                        /* next line has "width height" */
1319                         ncols = (int) strtol(pipeline, &endptr, 10);        /* convert width */
1320                         nrows = (int) strtol(endptr, NULL, 10);        /* and convert height */
1321                         break;
1322                 }                                                /* and we're ready to pixelize... */
1323                 if (strstr(pipeline, magicnumber) != NULL)        /* found magicnumber */
1324                         gotmagic = 1;                /* set flag */
1325         }                                                        /* --- end-of-while(1) --- */
1326 /* ---
1327  * allocate pixels and xlate remainder of pipe
1328  * ---------------------------------------------- */
1329 /* --- allocate pixels --- */
1330         npixels = nrows * ncols;        /* that's what we need */
1331         if (npixels < 1 || npixels > 999999)
1332                 goto end_of_job;                /* sanity check */
1333         if ((pixels = (BYTE *) malloc(npixels))        /* ask for it if not insane */
1334                 == NULL)
1335                 goto end_of_job;                /* and quit if request denied */
1336 /* --- xlate remainder of pipe --- */
1337         while (1) {                                        /* read lines (shouldn't find eof) */
1338                 /* --- read next line --- */
1339                 if (fgets(pipeline, 511, wget) == NULL) {        /* premature eof */
1340                         free(pixels);
1341                         pixels = NULL;                /* failed to xlate completely */
1342                         goto end_of_job;
1343                 }
1344                 /* free, reset return ptr, quit */
1345                 /* --- xlate 0's and 1's on the line --- */
1346                 pipeptr = pipeline;                /* start at beginning of line */
1347                 while (ipixel < npixels) {
1348                         while (*pipeptr != '\000')        /* skip leading non-digits */
1349                                 if (isdigit(*pipeptr))
1350                                         break;                /* done at first digit */
1351                                 else
1352                                         pipeptr++;        /* or skip leading non-digit */
1353                         if (*pipeptr == '\000')
1354                                 break;                        /* no more numbers on this line */
1355                         pixval = (int) strtol(pipeptr, &endptr, 10);        /*convert next num to 0 or 1 */
1356                         pixels[ipixel++] = (BYTE) pixval;        /* let's hope it's 0 or 1, anyway */
1357                         pipeptr = endptr;        /* move on to next number */
1358                 }                                                /* --- end-of-while(ipixels<npixels) --- */
1359                 if (ipixel >= npixels)
1360                         break;                                /* pixelized image complete */
1361         }                                                        /* --- end-of-while(1) --- */
1362 /* ---
1363  * end-of-job
1364  * ------------- */
1365 /* --- dropped through if completed successfully --- */
1366         if (width != NULL)
1367                 *width = ncols;                        /* supply width to caller */
1368         if (height != NULL)
1369                 *height = nrows;                /* supply height to caller */
1370 /* --- or jumped here if failed --- */
1371   end_of_job:
1372         if (wget != NULL)
1373                 pclose(wget);                        /* close pipe (if open) */
1374         return (pixels);                        /* back with pixelized expression */
1375 }                                                                /* --- end-of-function plainmimetext() --- */
1376 
1377 
1378 /* ==========================================================================
1379  * Function:        overlay ( pix1,w1,h1, pix2,w2,h2, col1,row1, bg,fg )
1380  * Purpose:        gif helper function, overlays pix2 onto pix1,
1381  *                with pix2's upper-left corner at col1,row1 of pix1,
1382  *                returning a new pix image with pix1's dimensions
1383  *                (pix2 is "truncated" if it extends beyond pix1's boundaries).
1384  * --------------------------------------------------------------------------
1385  * Arguments:        pix1 (I)        BYTE * to original image, presumably
1386  *                                passed to putgif() by user
1387  *                w1, h1 (I)        ints containing width, height of pix1 image
1388  *                pix2 (I)        BYTE * to overlay image, presumably
1389  *                                containing "plaintext" or whatever
1390  *                w1, h1 (I)        ints containing width, height of pix2 image
1391  *                col1, row1 (I)        ints containing upper-left corner on pix1
1392  *                                where pix2's first byte is placed,
1393  *                                i.e., col1=0,row1=0 for upper-left corners
1394  *                                to coincide. Special alignment directives:
1395  *                                  center horiz,vert if col1<0,row1<0
1396  *                                  place at right,bottom if col1>w1,row1>h1
1397  *                bg, fg (I)        ints containing
1398  *                                  bg color index for 0's in pix2
1399  *                                  fg color index for 1's in pix2
1400  * --------------------------------------------------------------------------
1401  * Returns:        ( BYTE * )        newly allocated pix array with pix1's
1402  *                                w1,h1-dimensions, containing a copy of pix1,
1403  *                                overlaid with pix2, as above.
1404  *                                any out-of-bounds pix2 pixels are discarded.
1405  * --------------------------------------------------------------------------
1406  * Notes:     o        Caller must free(returned_pix) when finished with them.
1407  * ======================================================================= */
1408 /* ---
1409  * entry point
1410  * -------------- */
overlay(BYTE * pix1,int w1,int h1,BYTE * pix2,int w2,int h2,int col1,int row1,int bg,int fg)1411 BYTE *overlay(BYTE * pix1, int w1, int h1, BYTE * pix2, int w2, int h2,
1412                           int col1, int row1, int bg, int fg)
1413 {
1414 /* ---
1415  * allocations and declarations
1416  * ------------------------------- */
1417         int npixels = (pix1 == NULL || pix2 == NULL || w1 < 1 || w2 < 1 ? 0 : w1 * h1);        /* #pixels */
1418         BYTE *pix = (npixels < 1
1419                                  || npixels > 999999 ? NULL : (BYTE *) malloc(npixels));
1420         int col = 0, row = 0;                /* pix2 col,row indexes */
1421 /* ---
1422  * initialization
1423  * ----------------- */
1424 /* --- check args --- */
1425         if (pix == NULL)
1426                 goto end_of_job;                /* bad args or malloc failed */
1427 /* --- init pix = pix1 --- */
1428         memcpy((void *) pix, (void *) pix1, npixels);        /* pix = pix1 to begin with */
1429 /* --- centering requested? --- */
1430         if (col1 < 0)
1431                 col1 = max2(0, (w1 - w2 + 1) / 2);        /* horizontal centering */
1432         if (row1 < 0)
1433                 row1 = max2(0, (h1 - h2 + 1) / 2);        /*  vertical centering  */
1434 /* --- check right, bottom edges --- */
1435         if (col1 + w2 > w1)
1436                 col1 = max2(0, w1 - w2);        /* text went past right of image */
1437         if (row1 + h2 > h1)
1438                 row1 = max2(0, h1 - h2);        /* text went below bottom */
1439 /* ---
1440  * now overlay pix2
1441  * ------------------- */
1442         for (row = 0; row < h2; row++) {        /* loop over each pix2 row */
1443                 int ipix1 = w1 * (row1 + row) + col1,        /* first pix1 col for this row */
1444                         ipix2 = w2 * row;        /* first pix2 col for this row */
1445                 if (row1 + row >= h1)
1446                         break;                                /* past bottom edge of pix1 */
1447                 for (col = 0; col < w2; col++) {        /* and over each col in row */
1448                         if (col1 + col >= w1)
1449                                 break;                        /* past right edge of pix1 */
1450                         pix[ipix1 + col] =        /* overlay pix2 pixel onto pix... */
1451                                 (pix2[ipix2 + col] == 0 ? bg : fg);        /* with bg index if pix2=0, else fg */
1452                 }                                                /* --- end-of-for(col) --- */
1453         }                                                        /* --- end-of-for(row) --- */
1454   end_of_job:
1455         return (pix);
1456 }                                                                /* --- end-of-function overlay() --- */
1457 
1458 
1459 /* ==========================================================================
1460  * Functions:        putgifcolortable  ( GS *gs, int *colors )
1461  *                putgifapplication ( GS *gs, GIFAPPLICATION *ga )
1462  * Purpose:        write gif blocks
1463  * --------------------------------------------------------------------------
1464  * Arguments:        gs (I)                (GS *) to gifsave89 data struct
1465  *        For putgifcolortable()...
1466  *                colors (I)        int * containing r,g,b, r,g,b, ..., -1
1467  *                                values 0-255 for color index 0, 1, ...,
1468  *                                up to max 256, terminated by any negative
1469  *                                number. Any trailing ...,r,-1 or ...,r,g,-1
1470  *                                is truncated. And the number of colors
1471  *                                supplied must be a power of 2; if not, it's
1472  *                                reduced to the next lower number that is.
1473  *        For putgifapplication()...
1474  *                ga (I)                (GIFAPPLICATION *) to application extension
1475  *                                containing header data to be written.
1476  *                                Caller must write actual data subblocks.
1477  * --------------------------------------------------------------------------
1478  * Returns:        ( int )                putgifcolortable returns #bits+1 required
1479  *                                to store the largest colors[] index,
1480  *                                others return 1 for successful completion,
1481  *                                or all return -1 for any error.
1482  * --------------------------------------------------------------------------
1483  * Notes:     o        structs can't be output as, e.g.,
1484  *                  memcpy((void *)image,(void *)&struct,sizeof(struct));
1485  *                unless we're absolutely sure the struct is packed.
1486  *                Since that's unfortunately not completely portably possible,
1487  *                these funcs output each member element separately.
1488  *              o        putgifcolortable() can be called with GS=NULL, in which
1489  *                case it outputs nothing, but returns the #bits+1 required
1490  *                to store the largest colors[] index.
1491  * ======================================================================= */
1492 /* ---
1493  * entry point
1494  * -------------- */
1495 //int putgifcolortable(GS * gs, unsigned char *colors, int ncolors)
putgifcolortable(GS * gs,int * colors)1496 int putgifcolortable(GS * gs, int *colors)
1497 {
1498 /* --- allocations and declarations --- */
1499         int ncolors = 0,                        /* #colors in colors[] table */
1500                 ncolorbits = (0);                /* #bits+1 for colors[] index */
1501         BK *bk = (gs == NULL ? NULL : &(gs->gifimage));        /* ptr to gif image block */
1502         int status = 1, putblkbyte();        /* one byte for each rgb component */
1503 /* --- force #colors to power of 2, count #bits for color index --- */
1504         if (colors != NULL) {                /* caller supplied r,g,b colors[] */
1505                 int pow2 = 2;                        /* power of 2 strictly > ncolors */
1506                 while (colors[ncolors] >= 0)
1507                         ncolors++;                        /* count r,g,b, r,g,b, ..., -1 */
1508                 ncolors = (ncolors / 3);        /* truncate trailing r or r,g */
1509                 ncolors = min2(256, max2(0, ncolors));        /* 0 <= ncolors <= 256 */
1510                 if (ncolors > 1) {                /* at least 2 colors */
1511                         while (ncolors >= pow2) {        /* power of 2 strictly > ncolors */
1512                                 pow2 *= 2;
1513                                 ncolorbits++;
1514                         }                                        /* bump power of 2 and #bits */
1515                         ncolors = pow2 / 2;
1516                 }                                                /* scale back ncolors */
1517         }                                                        /* --- end-of-if(colors!=NULL) --- */
1518         if (gs != NULL)                                /* caller wants color table written */
1519                 if (ncolors > 1) {                /* and provided colors[] to write */
1520                         int irgb = 0;                /* colors[] index for r,g,b triples */
1521                         if (ismsgprint(gs, 32))        /* (debug) msglevel>=32 */
1522                                 fprintf(gs->msgfp, "putgifcolortable> %d colors...\n",
1523                                                 ncolors);
1524                         for (irgb = 0; irgb < 3 * ncolors; irgb++) {        /* each component of each color */
1525                                 if (OKAY)
1526                                         status = putblkbyte(bk, colors[irgb]);        /* write byte */
1527                                 else
1528                                         break;                /* quit if failed */
1529                                 if (ismsgprint(gs, 32))        /* (debug) msglevel>=32 */
1530                                         if (irgb % 3 == 0) {        /* one color per set of 3 r,g,b */
1531                                                 char newline =        /* 6 per line */
1532                                                         ((irgb + 3) % 18 == 0
1533                                                          || irgb + 3 == 3 * ncolors ? '\n' : ' ');
1534                                                 fprintf(gs->msgfp, "%3d:%2x,%2x,%2x%c", irgb / 3,
1535                                                                 colors[irgb], colors[irgb + 1],
1536                                                                 colors[irgb + 2], newline);
1537                                         }
1538                         }                                        /* --- end-of-for(irgb) --- */
1539                         if (!OKAY)
1540                                 ncolorbits = (-1);        /* signal failure */
1541                 }
1542         /* --- end-of-if(gs!=NULL&&ncolors>1) --- */
1543         /*end_of_job: */
1544         return (ncolorbits);                /* return #bits for color index */
1545 }                                                                /* --- end-of-function putgifcolortable() --- */
1546 
1547 /* ---
1548  * entry point
1549  * -------------- */
putgifapplication(GS * gs,GIFAPPLICATION * ga)1550 int putgifapplication(GS * gs, GIFAPPLICATION * ga)
1551 {
1552 /* --- allocations and declarations --- */
1553         int status = (1);                        /* init signalling okay */
1554         int Introducer = 0x21;                /* always 0x21 */
1555         int Label = 0xFF;                        /* always 0xFF */
1556         int BlockSize = 0x0B;                /* always 0x0B */
1557         int Terminator = 0x00;                /* always 0x00 */
1558         BK *bk = (gs == NULL ? NULL : &(gs->gifimage));        /* ptr to gif image block */
1559         int putblkbytes(), putblkbyte(), putblkword();        /* write to image block */
1560 /* ---
1561  * Graphic Control Extension Block
1562  * ---------------------------------- */
1563         if (ga == NULL)
1564                 goto end_of_job;
1565         if (OKAY)
1566                 status = putblkbyte(bk, Introducer);
1567         if (OKAY)
1568                 status = putblkbyte(bk, Label);
1569         if (OKAY)
1570                 status = putblkbyte(bk, BlockSize);
1571         if (OKAY)
1572                 status = putblkbytes(bk, ga->Identifier, 8);
1573         if (OKAY)
1574                 status = putblkbytes(bk, ga->AuthentCode, 3);
1575         if (OKAY && 0)
1576                 status = putblkbyte(bk, Terminator);
1577   end_of_job:
1578         return (status);                        /* signal 1=success/-1=failure */
1579 }                                                                /* --- end-of-function putgifapplication() --- */
1580 
1581 
1582 /* ==========================================================================
1583  * Functions:        encodelzw ( GS *gs, int codesize, int nbytes, BYTE *data )
1584  *                clearlzw  ( GS *gs, int codesize )
1585  *                putlzw    ( GS *gs, int index, int byte )
1586  *                getlzw    ( GS *gs, int index, int byte )
1587  * Purpose:        lzw encoder
1588  * --------------------------------------------------------------------------
1589  * Arguments:        gs (I)                (GS *) to gifsave89 data struct
1590  *                                containing BLOCK buffer where lzw-encoded
1591  *                                data will be stored.
1592  *        For encodelzw(), clearlzw()...
1593  *                codesize (I)        int containing initial string table codesize
1594  *        For encodelzw()...
1595  *                nbytes (I)        integer containing #bytes to be lzw-encoded
1596  *                data (I)        (BYTE *) pointer to bytes to be lzw-encoded
1597  *        For putlzw(), getlzw()...
1598  *                index (I)        int containing string table index of
1599  *                                current prefix string
1600  *                byte (I)        (int)-type integer interpreted as (BYTE)byte
1601  *                                containing last byte after prefix
1602  * --------------------------------------------------------------------------
1603  * Returns:        ( int )
1604  * --------------------------------------------------------------------------
1605  * Notes:     o
1606  * ======================================================================= */
1607 /* ---
1608  * entry point
1609  * -------------- */
encodelzw(GS * gs,int codesize,int nbytes,BYTE * data)1610 int encodelzw(GS * gs, int codesize, int nbytes, BYTE * data)
1611 {
1612         int clearcode = POW2(codesize),
1613                 endofdata = clearcode + 1,
1614                 codebits = codesize + 1, limit = POW2(codebits) - 1;
1615         int prefix = NEXTFIRST, hashindex = 0;
1616         int clearlzw(), putlzw(), getlzw(), putsubblock(), flushsubblock();
1617         SB *sb = (gs == NULL ? NULL : &(gs->gifsubblock));        /* ptr to gif subblock */
1618         int byte = 0, ibyte = 0,        /* bytes from input data[] */
1619                 maxbyte = (gs == NULL ? 0 : POW2(gs->ncolorbits) - 1),        /* max index */
1620                 nblkbytes = (gs == NULL ? 0 : gs->gifimage.nblkbytes);        /* size at start */
1621 /* ---
1622  * check input
1623  * -------------- */
1624         if (gs == NULL)
1625                 goto end_of_job;                /* no gs data struct */
1626         if (data == NULL || nbytes < 1)
1627                 goto end_of_job;                /* no data to encode */
1628 /* ---
1629  * first init string table,
1630  * and output code telling the decoder to clear it, too
1631  * ---------------------------------------------------- */
1632         clearlzw(gs, codesize);                /* clear lzw string table */
1633         putsubblock(sb, clearcode, codebits);        /* tell decoder to clear it */
1634 /* --- pack image --- */
1635         for (ibyte = 0; ibyte < nbytes; ibyte++) {
1636                 byte = ((int) data[ibyte]);        /* current data byte */
1637                 if (byte > maxbyte)
1638                         byte = 0;                        /* default if byte too big */
1639                 /* ---
1640                  * if the string already exists in the table,
1641                  * just make this string the new prefix
1642                  * ------------------------------------------ */
1643                 if ((hashindex = getlzw(gs, prefix, byte)) != HASHFREE) {
1644                         prefix = hashindex;        /* oldprefix+byte already in table */
1645                         continue;
1646                 }
1647                 /* try adding next byte to prefix */
1648                 /* ---
1649                  * otherwise, the string does not exist in the table
1650                  * first, output code of the old prefix
1651                  * ------------------------------------------------- */
1652                 putsubblock(sb, prefix, codebits);
1653                 /* ---
1654                  * second, add the new string (prefix + new byte)
1655                  * to the string table (note variable length table)
1656                  * --------------------------------------------------- */
1657                 if (putlzw(gs, prefix, byte) > limit) {        /* too many strings for codesize */
1658                         if (++codebits > CODEBITS) {
1659                                 putsubblock(sb, clearcode, codebits - 1);
1660                                 clearlzw(gs, codesize);
1661                                 codebits = codesize + 1;
1662                         }
1663                         limit = POW2(codebits) - 1;
1664                 }
1665                 /* ---
1666                  * finally, reset prefix to a string containing only the new byte
1667                  * (since all one-byte strings are in the table, don't check for it)
1668                  * ------------------------------------------------------------------- */
1669                 prefix = byte;
1670         }                                                        /* --- end-of-for(ibyte) --- */
1671 /* -- end of data, write last prefix --- */
1672         if (prefix != NEXTFIRST)        /*one-byte strings already in table */
1673                 putsubblock(sb, prefix, codebits);
1674 /* --- write end-of-data signal, and flush the buffer --- */
1675         putsubblock(sb, endofdata, codebits);
1676         flushsubblock(sb);
1677   end_of_job:
1678         return ((gs == NULL ? 0 : gs->gifimage.nblkbytes - nblkbytes));        /*#bytes encoded */
1679 }                                                                /* --- end-of-function encodelzw() --- */
1680 
1681 /* ---
1682  * entry point
1683  * -------------- */
clearlzw(GS * gs,int codesize)1684 int clearlzw(GS * gs, int codesize)
1685 {
1686         int ncodes = RESCODES + ((int) (1 << codesize)),        /* # one-char codes */
1687                 putlzw(),                                /* insert all one-char codes */
1688                 index;                                        /* table index */
1689 /* --- no strings in the table --- */
1690         gs->nstrings = 0;
1691 /* --- mark entire hashtable as free --- */
1692         for (index = 0; index < HASHSIZE; index++)
1693                 gs->strhash[index] = HASHFREE;
1694 /* --- insert 2**codesize one-char strings, and reserved codes --- */
1695         for (index = 0; index < ncodes; index++)
1696                 putlzw(gs, NEXTFIRST, index);
1697         return (1);                                        /* back to caller */
1698 }                                                                /* --- end-of-function clearlzw() --- */
1699 
1700 /* ---
1701  * entry point
1702  * -------------- */
putlzw(GS * gs,int index,int byte)1703 int putlzw(GS * gs, int index, int byte)
1704 {
1705         int newindex = gs->nstrings,        /* init returned index */
1706                 hashindex = HASH(index, byte);        /* init hash for new string */
1707 /* --- string table out-of-memory? --- */
1708         if (gs->nstrings >= NSTRINGS) {        /* too many strings in table */
1709                 newindex = HASHFREE;
1710                 goto end_of_job;
1711         }
1712         /* signal error to caller */
1713         /* --- find free postion in string table --- */
1714         while (gs->strhash[hashindex] != HASHFREE)
1715                 hashindex = (hashindex + HASHSTEP) % HASHSIZE;
1716 /* --- insert new string and bump string table index --- */
1717         gs->strhash[hashindex] = gs->nstrings;
1718         gs->strbyte[gs->nstrings] = ((BYTE) byte);
1719         gs->strnext[gs->nstrings] = (index != NEXTFIRST) ? index : NEXTFIRST;
1720         gs->nstrings++;                                /* bump string table index */
1721 /* --- return index of new string --- */
1722   end_of_job:
1723         return (newindex);
1724 }                                                                /* --- end-of-function putlzw() --- */
1725 
1726 /* ---
1727  * entry point
1728  * -------------- */
getlzw(GS * gs,int index,int byte)1729 int getlzw(GS * gs, int index, int byte)
1730 {
1731         int hashindex = HASH(index, byte),        /* init the hash index */
1732                 nextindex;
1733 /* ---
1734  * if requested index is NEXTFREE (=0xFFFF), just return byte since
1735  * all one-character strings have their byte value as their index
1736  * ---------------------------------------------------------------- */
1737         if (index == NEXTFIRST)
1738                 return (((int) byte));
1739 /* ---
1740  * otherwise, search the string table until the string is found,
1741  * or we find HASHFREE, in which case the string does not exist
1742  * ------------------------------------------------------------- */
1743         while ((nextindex = gs->strhash[hashindex]) != HASHFREE) {
1744                 if (gs->strnext[nextindex] == index
1745                         && gs->strbyte[nextindex] == ((BYTE) byte))
1746                         return (nextindex);
1747                 hashindex = (hashindex + HASHSTEP) % HASHSIZE;
1748         }
1749 /* ---
1750  * string not in table
1751  * ------------------- */
1752         return (HASHFREE);                        /* signal "error" to caller */
1753 }                                                                /* --- end-of-function getlzw() --- */
1754 
1755 
1756 /* ==========================================================================
1757  * Functions:        putblkbytes ( BK *bk, BYTE *bytes, int nbytes )
1758  *                putblkbyte  ( BK *bk, int byte )
1759  *                putblkword  ( BK *bk, int word )
1760  * Purpose:        write bytes and integer words to data block,
1761  *                and reallocate block as necessary
1762  * --------------------------------------------------------------------------
1763  * Arguments:        bk (I/O)        (BK *) to BLOCK data struct, which
1764  *                                contains BYTE **block to buffer that's
1765  *                                first malloc()'ed and then realloc()'ed
1766  *                                as needed.
1767  *        For putblkbytes()...
1768  *                bytes (I)        (BYTE *) pointer to bytes to be stored
1769  *                nbytes (I)        integer containing #bytes to be stored
1770  *        For putblkbyte()...
1771  *                byte (I)        (int)-type integer interpreted as (BYTE)byte
1772  *                                to be stored in next buffer byte
1773  *        For putblkword()...
1774  *                word (I)        (int)-type integer whose two least
1775  *                                significant byte values are to be stored in
1776  *                                little-endian order (regardless of host order)
1777  * --------------------------------------------------------------------------
1778  * Returns:        ( int )                putblkbytes returns #bytes stored,
1779  *                                putblkbyte  returns 1 byte stored,
1780  *                                putblkword  returns 1 word stored,
1781  *                                or all return -1 for any error.
1782  * --------------------------------------------------------------------------
1783  * Notes:     o
1784  * ======================================================================= */
1785 /* ---
1786  * entry point
1787  * -------------- */
putblkbytes(BK * bk,BYTE * bytes,int nbytes)1788 int putblkbytes(BK * bk, BYTE * bytes, int nbytes)
1789 {
1790         int status = (-1);                        /* init to signal error */
1791         if (bk == NULL || bytes == NULL || nbytes < 1)
1792                 goto end_of_job;                /* check args */
1793 /* --- realloc gifimage as necessary --- */
1794         while (bk->nblkbytes + nbytes > bk->maxblkbytes) {        /* more room for nbytes */
1795                 int newsize =
1796                         (bk->nblkbytes <
1797                          1 ? MAXBLKBYTES : (3 * (bk->maxblkbytes)) / 2);
1798                 void *newblock = realloc((void *) (*(bk->block)), newsize);
1799                 if (newblock == NULL)
1800                         goto end_of_job;        /* failed to realloc */
1801                 *(bk->block) = (BYTE *) newblock;        /* store reallocated block ptr */
1802                 bk->maxblkbytes = newsize;
1803         }                                                        /* and its new larger size */
1804 /* --- copy caller's bytes --- */
1805         memcpy((void *) (*(bk->block) + bk->nblkbytes), bytes, nbytes);        /* copy bytes */
1806         bk->nblkbytes += nbytes;        /* bump byte count */
1807         status = nbytes;                        /* signal success */
1808   end_of_job:
1809         return (status);                        /* back with #bytes or -1=error */
1810 }                                                                /* --- end-of-function putblkbytes() --- */
1811 
1812 /* ---
1813  * entry point
1814  * -------------- */
putblkbyte(BK * bk,int byte)1815 int putblkbyte(BK * bk, int byte)
1816 {
1817         int putblkbytes();                        /* write byte */
1818         BYTE thisbyte[2];                        /* place caller's byte in string */
1819         thisbyte[0] = ((BYTE) byte);        /* caller's byte */
1820         thisbyte[1] = '\000';                /* (not really necessary) */
1821         return (putblkbytes(bk, thisbyte, 1));        /* back with #bytes=1 or -1=error */
1822 }                                                                /* --- end-of-function putblkbyte() --- */
1823 
1824 /* ---
1825  * entry point
1826  * -------------- */
putblkword(BK * bk,int word)1827 int putblkword(BK * bk, int word)
1828 {
1829         int putblkbytes();                        /* write bytes */
1830 /* --- byte values regardless of little/big-endian ordering on host --- */
1831         int lobyte = (abs(word)) % 256,        /* least significant byte */
1832                 hibyte = ((abs(word)) / 256) % 256;        /* next least significant byte */
1833         BYTE thisword[2];                        /* buffer for word's bytes */
1834 /* --- store little-endian ordering (least significant byte first) --- */
1835         thisword[0] = ((BYTE) lobyte);        /* low-order byte written first */
1836         thisword[1] = ((BYTE) hibyte);        /* high-order byte written second */
1837         return (putblkbytes(bk, thisword, 2));        /* store word */
1838 }                                                                /* --- end-of-function putblkword() --- */
1839 
1840 
1841 /* ==========================================================================
1842  * Functions:        putsubblock   ( SB *sb, int bits,  int nbits )
1843  *                putsubbytes   ( SB *sb, int bytes, int nbytes )
1844  *                flushsubblock ( SB *sb )
1845  * Purpose:        Bitwise operations to construct gif subblocks...
1846  *
1847  * --------------------------------------------------------------------------
1848  * Arguments:        sb (I/O)        (SB *) to SUBBLOCK data struct
1849  *                bits (I)        int whose low-order bits
1850  *                                are to be added at the end of subblock,
1851  *                                and then eventually flushed into block,
1852  *                                preceded by a byte count of the subblock
1853  *                nbits (I)        int containing number of bits to be stored
1854  *        For putsubbytes...
1855  *                bytes (I)        BYTE * for sequence of 8-bit bytes
1856  *                                to be added at the end of subblock
1857  *                nbytes (I)        int containing number of bytes to be stored
1858  * --------------------------------------------------------------------------
1859  * Returns:        ( int )                putsubblock    returns nbits,
1860  *                                putsubbytes    returns nbytes,
1861  *                                flushsubblock  returns #bytes flushed,
1862  *                                or both return -1 for any error.
1863  * --------------------------------------------------------------------------
1864  * Notes:     o        gif format stores image data in 255-byte subblocks,
1865  *                each preceded by a leading byte containing
1866  *                the number of data bytes in the subblock that follows.
1867  *                That's typically several 255-byte subblocks, and
1868  *                a final short subblock. That last subblock must be
1869  *                followed by a 0-byte (the byte count of the non-existent
1870  *                next subblock) signalling end-of-data to the gif decoder.
1871  *              o        gif image data is typically lzw-encoded, done by
1872  *                the encodelzw() function above, and written several
1873  *                bits at a time, rather than in complete bytes.
1874  *              o        putsubblock() accommodates this behavior by
1875  *                accumulating bits into complete bytes, and then
1876  *                flushsubblock() writes full 255-byte subblocks
1877  *                (preceded by byte count) as necessary, whenever
1878  *                called by putsubblock().
1879  *              o        the final short subblock is written when flushsubblock()
1880  *                is called the by user, after his last call to putsubblock().
1881  *                It's also the user's responsibility to write the
1882  *                trailing 0-byte after calling flushsubblock().
1883  *                That's done by calling putblkbyte(bk,0) with the
1884  *                parent BLOCK *bk subblocks were written to.
1885  * ======================================================================= */
1886 /* ---
1887  * entry point
1888  * -------------- */
putsubblock(SB * sb,int bits,int nbits)1889 int putsubblock(SB * sb, int bits, int nbits)
1890 {
1891         int status = 0;                                /* returns nbits or signals error */
1892         int flushsubblock();                /* flush subblock when full */
1893         int indexlen = (sb == NULL ? 0 : (sb->index >= 0 ? 1 : 0));        /* >=0 to write index# */
1894         if (sb != NULL)                                /* make sure we have subblock */
1895                 while (1) {                                /* finished after nbits */
1896                         /* ---
1897                          * flush subblock whenever full
1898                          * ---------------------------- */
1899                         if (sb->nsubbytes + indexlen >= SUBBLOCKSIZE)        /* subblock full */
1900                                 if (flushsubblock(sb) == (-1)) {        /* flush subblock, check for error */
1901                                         status = (-1);
1902                                         break;
1903                                 }
1904                         /* and signal error on failure */
1905                         /* ---
1906                          * remaining bits fit in current byte, or fill current byte and continue
1907                          * --------------------------------------------------------------------- */
1908                         if (nbits < 1)
1909                                 break;                        /* done after all bits exhausted */
1910                         else {                                /* or still have bits for gifblock */
1911                                 /* ---fieldbits is lesser of remaining nbits, or #bits left in byte--- */
1912                                 int freebits = BITSPERBYTE - sb->nsubbits,        /*#unused bits in this byte */
1913                                         fieldbits = (nbits <= freebits ? nbits : freebits);        /*#bits for this byte */
1914                                 /* subblock[nsubbytes] |= ((bits&(bitmask(fieldbits))) << nsubbits); */
1915                                 putbitfield(sb->subblock[sb->nsubbytes], sb->nsubbits,
1916                                                         fieldbits, bits);
1917                                 bits >>= fieldbits;        /* shift out the bits we just used */
1918                                 nbits -= fieldbits;        /* fewer bits remaining */
1919                                 sb->nsubbits += fieldbits;        /* more bits used in current byte */
1920                                 if (sb->nsubbits >= BITSPERBYTE) {        /*byte exhausted, move on to next */
1921                                         sb->nsubbits = 0;
1922                                         sb->nsubbytes++;
1923                                 }                                /* first bit of next byte */
1924                                 status += fieldbits;
1925                         }                                        /* update status */
1926                 }                                                /* --- end-of-while(1) --- */
1927         return (status);                        /* back with #bits or -1=error */
1928 }                                                                /* --- end-of-function putsubblock() --- */
1929 
1930 /* ---
1931  * entry point
1932  * -------------- */
putsubbytes(SB * sb,BYTE * bytes,int nbytes)1933 int putsubbytes(SB * sb, BYTE * bytes, int nbytes)
1934 {
1935         int status = 0;                                /* returns nbits or signals error */
1936         int ibyte = 0, putsubblock();        /* just store each byte as 8 bits */
1937         if (sb != NULL && bytes != NULL && nbytes > 0)        /* data check */
1938                 for (ibyte = 0; ibyte < nbytes; ibyte++) {        /* put one 8-bit byte at a time */
1939                         status = putsubblock(sb, ((int) (bytes[ibyte])), BITSPERBYTE);        /*thisbyte */
1940                         if (!OKAY)
1941                                 break;
1942                 }                                                /* quit if failed */
1943         return ((OKAY ? nbytes : status));        /* back with #bytes or -1=error */
1944 }                                                                /* --- end-of-function putsubbytes() --- */
1945 
1946 /* ---
1947  * entry point
1948  * -------------- */
flushsubblock(SB * sb)1949 int flushsubblock(SB * sb)
1950 {
1951         int status = (-1);                        /* init to signal error */
1952         BK *bk = (sb == NULL ? NULL : sb->block);        /* ptr to parent block */
1953         int index = (sb == NULL ? (-1) : sb->index);        /* >=0 to write index# */
1954         int nflush = (sb == NULL ? (-1) :        /* #bytes in subblock to be flushed */
1955                                   (sb->nsubbytes + (sb->nsubbits == 0 ? 0 : 1)));
1956         int putblkbyte(), putblkbytes();        /* write subblock to block */
1957         if (nflush < 1)                                /* nothing to flush or error */
1958                 status = nflush;                /* return 0 or -1=error to caller */
1959         else {                                                /* have data in subblock */
1960                 int indexlen = (index >= 0 ? 1 : 0);        /* and maybe extra byte for index# */
1961                 /* --- trap internal error --- */
1962                 if (nflush + indexlen > SUBBLOCKSIZE)
1963                         nflush = SUBBLOCKSIZE - indexlen;
1964                 /* --- first, emit leading byte containing number of bytes to follow --- */
1965                 if (putblkbyte(bk, nflush + indexlen) == (-1))
1966                         goto end_of_job;        /*failed? */
1967                 /* --- next, subblock index#, if desired --- */
1968                 if (index >= 0) {                /* index# desired */
1969                         if (++index > 255)
1970                                 index = 1;                /* bump index#, wrap to 1 after 255 */
1971                         if (putblkbyte(bk, index) == (-1))
1972                                 goto end_of_job;        /*quit if failed */
1973                         sb->index = index;
1974                 }
1975                 /* store bumped index# */
1976                 /* --- finally, the subblock bytes themselves  --- */
1977                 if (putblkbytes(bk, sb->subblock, nflush) != (-1)) {        /* okay */
1978                         memset(sb->subblock, 0, SUBBLOCKSIZE);        /* clear the subblock */
1979                         sb->nsubbytes = sb->nsubbits = 0;        /* reset subblock indexes */
1980                         status = nflush;
1981                 }                                                /* signal success */
1982         }                                                        /* --- end-of-if(nflush>=1) --- */
1983   end_of_job:
1984         return (status);                        /* back with #bytes or -1=error */
1985 }                                                                /* --- end-of-function flushsubblock() --- */
1986 
1987 
1988 /* ==========================================================================
1989  * Functions:        gifwidth  ( gs )
1990  *                gifheight ( gs )
1991  * Purpose:        user utility functions
1992  *                  returns width, height of gif
1993  *                  (for caller's function that doesn't know gs structure)
1994  * --------------------------------------------------------------------------
1995  * Arguments:        gs (I)                void *address of GS struct,
1996  *                                which we'll interpret for caller
1997  * --------------------------------------------------------------------------
1998  * Returns:        ( int )                gs->width or gs->height, as appropriate,
1999  *                                or 0 for any error.
2000  * --------------------------------------------------------------------------
2001  * Notes:     o
2002  * ======================================================================= */
2003 /* --- entry points --- */
gifwidth(void * gs)2004 int gifwidth(void *gs)
2005 {
2006         return ((gs == NULL ? 0 : ((GS *) gs)->width));
2007 }
2008 
gifheight(void * gs)2009 int gifheight(void *gs)
2010 {
2011         return ((gs == NULL ? 0 : ((GS *) gs)->height));
2012 }
2013 
2014 
2015 /* ==========================================================================
2016  * Function:        pixgraph ( ncols, nrows, f, n )
2017  * Purpose:        user utility function
2018  *                  generates pixels for putgif()
2019  *                  representing a simple graph of f[0]...f[n-1]
2020  * --------------------------------------------------------------------------
2021  * Arguments:        ncols (I)        int containing width of gif image
2022  *                nrows (I)        int containing height of gif image
2023  *                f (I)                double *  to values to be graphed
2024  *                n (I)                int  containing number of f-values
2025  * --------------------------------------------------------------------------
2026  * Returns:        ( BYTE * )        malloc'ed buffer of nrows*ncols pixels,
2027  *                                or NULL for any error.
2028  * --------------------------------------------------------------------------
2029  * Notes:     o
2030  * ======================================================================= */
2031 /* --- entry point --- */
pixgraph(int ncols,int nrows,double * f,int n)2032 BYTE *pixgraph(int ncols, int nrows, double *f, int n)
2033 {
2034 /* --- allocations and declarations --- */
2035         int maxpixels = 1000000, npixels = (ncols < 1 || nrows < 1 ? 0 : min2(ncols * nrows, maxpixels));        /*#bytes */
2036         BYTE *pixels = (BYTE *) (npixels < 1 ? NULL : malloc(npixels));        /*malloc buffer */
2037         int row = 0, col = 0;                /* row=y,col=x pixel coords */
2038         double bigf = 0.0;                        /* largest f-value */
2039 /* --- initialize pixels and check input --- */
2040         if (pixels == NULL)
2041                 goto end_of_job;                /* malloc failed (or input error) */
2042         memset(pixels, 0, npixels);        /* clear pixel bytes (bg=0 assumed) */
2043         if (f == NULL || n < 1)
2044                 goto end_of_job;                /* nothing to graph */
2045 /* ---
2046  * set pixels representing f[]
2047  * ------------------------------ */
2048         for (col = 0; col < n; col++)
2049                 if (absval(f[col]) > bigf)
2050                         bigf = absval(f[col]);
2051         for (row = 0; row < nrows; row++) {
2052                 double yval =
2053                         bigf * ((double) ((nrows / 2) - row)) / ((double) (nrows / 2));
2054                 for (col = 0; col < ncols; col++) {
2055                         int i = (col * (n - 1)) / ncols;
2056                         int ipixel = min2(row * ncols + col, maxpixels);
2057                         if (yval * f[i] >= yval * yval)
2058                                 pixels[ipixel] = ((BYTE) 1);
2059                 }
2060         }                                                        /* --- end-of-for(row) --- */
2061   end_of_job:
2062         return (pixels);                        /* caller should free(pixels) */
2063 }                                                                /* --- end-of-function pixgraph() --- */
2064 
2065 
2066 #if defined(GSTESTDRIVE)
2067 /* ==========================================================================
2068  * Function:        main ( int argc, char *argv[] )
2069  * Purpose:        test driver for gifsave89
2070  * --------------------------------------------------------------------------
2071  * Arguments:        argc (I)        as usual.
2072  *                argv (I)        Also see "command-line args" in main()
2073  *                                argv[1] = test#, 1 or 2
2074  *                                           for test#1   for test#2
2075  *                                        -----------------------------
2076  *                                argv[2] =   #rows        #frames
2077  *                                argv[3] =   #cols     disposal method
2078  *                                argv[4] =  filename      filename
2079  * --------------------------------------------------------------------------
2080  * Returns:        ( int )                always 0
2081  *                Also writes file gifsave89test.gif, if you don't specify
2082  *                an alternative filename. Just typing
2083  *                  ./gifsave89
2084  *                outputs a single waveform image, 300x300 pixels, to the file.
2085  *                Typing
2086  *                  ./gifsave89 2
2087  *                outputs an animation sequence comprising 50 frames.
2088  *                See "command-line args" in main() for further details.
2089  * --------------------------------------------------------------------------
2090  * Notes:     o        See http://www.forkosh.com/gifsave89.html
2091  *                for a more detailed discussion of the following information.
2092  *              o        Compile gifsave89 as
2093  *                  cc -DGSTESTDRIVE gifsave89.c -lm -o gifsave89
2094  *                for an executable image with this main() test driver, or as
2095  *                  cc yourprogram.c gifsave89.c -o yourprogram
2096  *                for use with your own program (-lm no longer necessary
2097  *                unless yourprogram needs it).
2098  *                -------------- gifsave89 usage instructions -----------------
2099  *              o        main() is a short program illustrating simple gifsave89 usage
2100  *                (the hard part is usually generating the pixels).
2101  *              o        The typical sequence of gifsave function calls is...
2102  *                  First, call
2103  *                    gs = newgif(&gifimage,ncols,nrows,colortable,bgindex)
2104  *                  Next, optionally call
2105  *                    animategif(gs,nrepetitions,delay,tcolor,disposal)
2106  *                  Now, once or in a loop {
2107  *                    optionally call  controlgif(gs,etc)
2108  *                    always     call  putgif(gs,pixels) }
2109  *                  Finally, call
2110  *                    nbytes = endgif(gs)
2111  *                  Now do what you want with gifimage[nbytes],
2112  *                    and then free(gifimage)
2113  *              o        Note that void *newgif() returns a ptr that must be passed
2114  *                as the first argument to every subsequent gifsave89 function
2115  *                called.
2116  *              o        Minimal usage example/template...
2117  *                  void *gs=NULL, *newgif();
2118  *                  int  nbytes=0, putgif(), endgif();
2119  *                  int  ncols=255, nrows=255,
2120  *                       *colortable = { 255,255,255, 0,0,0, -1 },
2121  *                       bgindex=0;
2122  *                  unsigned char *pixels = { 0,1,0,1, ..., ncols*nrows };
2123  *                  unsigned char *gifimage = NULL;
2124  *                  gs = newgif(&gifimage,ncols,nrows,colortable,bgindex);
2125  *                  if ( gs != NULL ) {
2126  *                    putgif(gs,pixels);
2127  *                    nbytes = endgif(gs); }
2128  *                  if ( nbytes > 0 ) {
2129  *                    do_what_you_want_with(gifimage,nbytes);
2130  *                    free(gifimage); }
2131  *                ---------------- gifsave89 data elements --------------------
2132  *              o        unsigned char pixels[nrows*ncols]; which you may malloc(),
2133  *                is always a sequence of bytes in row order, i.e.,
2134  *                pixels[0] corresponds to the upper-left corner pixel,
2135  *                pixels[ncols] to the leftmost pixel of the second row, ...
2136  *                pixels[nrows*ncols-1] to the lower-right corner pixel.
2137  *              o        Each pixels[] byte contains the color table index,
2138  *                described immediately below, for the corresponding pixel.
2139  *              o        int colortable[] = { r0,g0,b0, r1,g1,b1, r2,g2,b2, ..., -1 };
2140  *                is a sequence of ints, each one 0 to 255, interpreted as
2141  *                r,g,b-values. Terminate the sequence with any negative number.
2142  *              o        The first three colortable[] numbers are the
2143  *                r,g,b values for any pixel=pixels[ipixel]  whose value is 0,
2144  *                the second three for any pixel whose value is 1, etc.
2145  *              o        The number of colors in colortable[] must be a power of 2,
2146  *                e.g., you must have 6 (for 2 colors), or 12 (for 4), or etc,
2147  *                numbers in colortable[] preceding the -1.
2148  *              o        Simple usage is int colortable[] = {255,255,255, 0,0,0, -1};
2149  *                for monochrome pixel=0/white, pixel=1/black.
2150  *                And, obviously, pixel values must be between 0 and #colors-1.
2151  *                --------------------- animation note ------------------------
2152  *              o        For animated gifs, you'd typically expect to call controlgif()
2153  *                before each putgif() frame, specifying delay=0,disposal=2.
2154  *                That's not necessary: gifsave89 automatically emits that
2155  *                graphic control extension for animated gifs if you haven't.
2156  * ======================================================================= */
2157 /* --- entry point --- */
main(int argc,char * argv[])2158 int main(int argc, char *argv[])
2159 {
2160 /* -------------------------------------------------------------------------
2161 Allocations and Declarations
2162 -------------------------------------------------------------------------- */
2163 /* ---
2164  * gifsave89 funcs declared below in typical calling sequence order
2165  * you'd typically need these vars to use gifsave89 in your own program...
2166  * ----------------------------------------------------------------------- */
2167 /* --- gifsave89 funcs --- */
2168         void *gs = NULL, *newgif();        /* allocate, init gifsave89 struct */
2169         void *gifimage = NULL, *makegif();        /* output generated by gifsave89 */
2170         int animategif(),                        /* "NETSCAPE""2.0" application ext */
2171          putgif(),                                        /* add (another) gif frame */
2172          nbytes = 0, endgif();                /* #bytes in generated gifimage */
2173 /* --- typical gifsave89 colortable --- */
2174         int colortable[] = { 255, 255, 255, 0, 0, 255,        /*bg(index0)=white,fg(1)=blue */
2175                 0, 255, 0, 255, 0, 0,        /* also colors 2=green, 3=red */
2176                 -1
2177         };                                                        /* end-of-colortable[] */
2178         int bgindex = 0;                        /* background colortable index */
2179 /* --- optional gifsave89 plaintext --- */
2180         int plaintxtgif();                        /* overlay text on image */
2181 /* --- optional verbosity (for debug) --- */
2182         int debuggif();                                /* set msglevel,msgfile */
2183 /* ---
2184  * additional funcs and variables for our tests...
2185  * ----------------------------------------------- */
2186 /* --- additional funcs --- */
2187         int nwritten = 0, writefile();        /* write test output file */
2188         BYTE *pixels = NULL, *pixgraph();        /* generate pixels for gif image */
2189         double *f(), fparam = 0.0, pi = 3.14159;        /* y=f(x) waveform for gif image */
2190 /* --- additional variables --- */
2191         int nvals = 500;                        /* #f-vals generated (all tests) */
2192         int iframe = 0;                                /* animation frame# (for test#2) */
2193         int istext = 0;                                /* true to issue plaintxtgif() */
2194 /* ---
2195  * command-line args
2196  * -------------------- */
2197         int testnum = (argc > 1 ? atoi(argv[1]) : 1);        /*testnum is first arg, or 1 */
2198 /* --- test#1 args --- */
2199         int nrows = (testnum == 1 && argc > 2 ? atoi(argv[2]) : 300),
2200                 ncols = (testnum == 1 && argc > 3 ? atoi(argv[3]) : 300);
2201 /* --- test#2 args --- */
2202         int nframes = (testnum == 2 && argc > 2 ? atoi(argv[2]) : 50),
2203                 nreps = (testnum == 2 && argc > 3 ? atoi(argv[3]) : 0);
2204 /* --- args for all tests --- */
2205         char *text = (argc > 4 ? argv[4] : "\000");        /* text to be overlaid */
2206         char *file = (argc > 5 ? argv[5] : "gifsave89test.gif");
2207 
2208 /* -------------------------------------------------------------------------
2209 test illustrating general gifsave89 usage
2210 -------------------------------------------------------------------------- */
2211 /* --- data checks --- */
2212         if (testnum != 2)
2213                 testnum = 1;                        /* input check: force test#1 or #2 */
2214         if (strlen(text) > 1)
2215                 istext = 1;                                /* have overlay text */
2216 /* --- set verbosity (to display gnu/gpl copyright) --- */
2217         debuggif(1, NULL);                        /* msglevel=1, msgfp=stdout */
2218 
2219 /* ---
2220  * testnum 1: single-frame gif of sample waveform y=f(x)
2221  * note how easy it is to use gifsave89
2222  * ------------------------------------------------------- */
2223         if (testnum == 1) {
2224                 /* ---generate pixels to be graphed (this is typically the hard part)--- */
2225                 if ((pixels = pixgraph(ncols, nrows, f(fparam, nvals), nvals))        /*get pixels */
2226                         == NULL)
2227                         goto end_of_job;        /* quit if failed */
2228                 /* ---"short form" creates gifimage of pixels with one function call--- */
2229                 if (!istext)                        /* one-line func call for gifimage */
2230                         gifimage =
2231                                 makegif(&nbytes, ncols, nrows, pixels, colortable,
2232                                                 bgindex);
2233                 /* --- or gifsave89 "long form" to include plaintext --- */
2234                 else if ((gs = newgif(&gifimage, ncols, nrows, colortable, bgindex))        /*init gifsave89 */
2235                                  !=NULL) {                /* if initialization succeeded */
2236                         plaintxtgif(gs, -1, -1, 0, 0, bgindex, 1, text);        /* overlay text */
2237                         putgif(gs, pixels);        /* add image */
2238                         nbytes = endgif(gs);
2239                 }                                                /* done */
2240         }
2241 
2242         /* --- end-of-if(testnum==1) --- */
2243         /* ---
2244          * testnum 2: same as testnum#1, except we animate gif frames
2245          * almost as easy
2246          * ----------------------------------------------------------- */
2247         if (testnum == 2) {
2248                 /* --- initialize gif as before (as for test#1) --- */
2249                 if ((gs = newgif(&gifimage, ncols, nrows, colortable, bgindex))        /*init gifsave89 */
2250                         == NULL)
2251                         goto end_of_job;        /* quit if failed */
2252                 /* --- but this time emit application extension for looped animation --- */
2253                 if (nreps >= 0)                        /* want looped animation? */
2254                         animategif(gs, nreps, 0, -1, 2);        /* emit application extension */
2255                 /* --- if requested, add same text to every frame --- */
2256                 if (istext)
2257                         plaintxtgif(gs, -1, -1, -1, -1, bgindex, 1, text);        /*overlay text */
2258                 /* --- now render frames comprising the animation --- */
2259                 for (iframe = 0; iframe < nframes; iframe++) {        /* render each frame */
2260                         if (iframe > 0)
2261                                 free((void *) pixels);        /* first free previous frame */
2262                         /* --- pixgraph() now generates different pixels for each frame --- */
2263                         fparam = 2. * pi * ((double) iframe) / ((double) (nframes));        /* 0<=fparam<2pi */
2264                         pixels = pixgraph(ncols, nrows, f(fparam, nvals), nvals);
2265                         /* --- putgif adds another frame to the animated gif --- */
2266                         putgif(gs, pixels);        /* add another frame image */
2267                 }                                                /* --- end-of-for(iframe) --- */
2268                 /* --- all frames written --- */
2269                 nbytes = endgif(gs);        /* done */
2270         }
2271 
2272 
2273         /* --- end-of-if(testnum==2) --- */
2274         /* -------------------------------------------------------------------------
2275            write gif image file and cleanup
2276            -------------------------------------------------------------------------- */
2277         /* ---save image to file for display with ImageMagic or other viewer--- */
2278         if (file != NULL) {
2279                 nwritten = writefile(gifimage, nbytes, file);
2280                 fprintf(stdout, "GIF image written to file: %s\n",
2281                                 (nwritten > 0 ? file : "**write failed**"));
2282         }
2283 /* --- cleanup --- */
2284         if (pixels != NULL)
2285                 free((void *) pixels);        /* free allocated pixels */
2286         if (gifimage != NULL)
2287                 free((void *) gifimage);        /* free allocated image */
2288 /* ----------------------------------------------------------------------- */
2289   end_of_job:
2290 /* ----------------------------------------------------------------------- */
2291         return (0);                                        /* bye-bye */
2292 }                                                                /* --- end-of-function main() --- */
2293 
2294 
2295 /* ==========================================================================
2296  * Function:        f ( param, n )
2297  * Purpose:        sample gif image function for gifgraph()
2298  * --------------------------------------------------------------------------
2299  * Arguments:        param (I)        double containing f-parameter
2300  *                n (I)                int containing #values wanted
2301  * --------------------------------------------------------------------------
2302  * Returns:        ( double * )        ptr to n static values of sample function
2303  * --------------------------------------------------------------------------
2304  * Notes:     o
2305  * ======================================================================= */
2306 /* --- entry points --- */
f(double param,int n)2307 double *f(double param, int n)
2308 {
2309         static double yvals[999];        /* returned vals */
2310         int ix = 0, iy = 0;                        /* yvals[ix] index, iy=harmonic# */
2311         double pi = 3.14159;
2312         n = max2(2, min2(999, n));        /* 2<=n<=999 */
2313         for (ix = 0; ix < n; ix++) {
2314                 double x = 2. * pi * ((double) ix) / ((double) n);        /* 0<=x<2pi */
2315                 double phase = param;        /* interpret param as phase */
2316                 yvals[ix] = 0.0;                /* init */
2317                 for (iy = 0; iy < 10; iy++) {        /* harmonics */
2318                         double y = ((double) (iy + 1));
2319                         yvals[ix] += sin(y * x + phase) * cos(x + y * phase);
2320                 }
2321         }                                                        /* --- end-of-for(ix) --- */
2322 /*end_of_job:*/
2323         return (yvals);
2324 }                                                                /* --- end-of-function f() --- */
2325 
2326 
2327 /* ==========================================================================
2328  * Function:        writefile ( buffer, nbytes, file )
2329  * Purpose:        emits buffer to file or to stdout
2330  * --------------------------------------------------------------------------
2331  * Arguments:        buffer (I)        (BYTE *)pointer to buffer of bytes to be
2332  *                                emitted
2333  *                nbytes (I)        int containing total #bytes from buffer
2334  *                                to be emitted
2335  *                file (I)        (char *)pointer to null-terminated
2336  *                                char string containing full path to
2337  *                                file where buffer will be written,
2338  *                                or NULL or empty string for stdout
2339  * --------------------------------------------------------------------------
2340  * Returns:        ( int )                #bytes emitted (!=nbytes signals error)
2341  * --------------------------------------------------------------------------
2342  * Notes:     o
2343  * ======================================================================= */
2344 /* --- entry point --- */
writefile(BYTE * buffer,int nbytes,char * file)2345 int writefile(BYTE * buffer, int nbytes, char *file)
2346 {
2347 /* -------------------------------------------------------------------------
2348 Allocations and Declarations
2349 -------------------------------------------------------------------------- */
2350         FILE *fileptr = stdout;                /* init to write buffer to stdout */
2351         int nwritten = 0;                        /* #bytes actually written */
2352 /* -------------------------------------------------------------------------
2353 initialization
2354 -------------------------------------------------------------------------- */
2355 /* --- check input --- */
2356         if (buffer == NULL                        /* quit if no input from caller */
2357                 || nbytes < 1)
2358                 goto end_of_job;                /* or no output requested */
2359 /* --- open file (or write to stdout) --- */
2360         if (file != NULL)                        /* have file arg */
2361                 if (*file != '\000')        /* file arg not an empty string */
2362                         if ((fileptr = fopen(file, "wb"))        /* open file for binary write */
2363                                 == (FILE *) NULL)
2364                                 fileptr = stdout;        /* revert to stdout if fopen fails */
2365 /* -------------------------------------------------------------------------
2366 write bytes from buffer and return to caller
2367 -------------------------------------------------------------------------- */
2368 /* --- write bytes from buffer to file (or to stdout) --- */
2369         nwritten = fwrite(buffer, sizeof(BYTE), nbytes, fileptr);        /* write bytes */
2370         if (fileptr != NULL && fileptr != stdout)
2371                 fclose(fileptr);                /* close file */
2372 /* --- back to caller --- */
2373   end_of_job:
2374         return (nwritten);                        /* back with #bytes written */
2375 }                                                                /* --- end-of-function writefile() --- */
2376 #endif
2377 /* ====================== END-OF-FILE GIFSAVE89.C ======================== */
2378