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