1 
2 /**********************************************************************
3  *	togif -
4  *		Convert an IRIS image to GIF format.  Converts b/w and
5  *	color images to 8 bit per pixel GIF format.  Color images
6  *	are dithered with a 4 by 4 dither matrix.  GIF image files
7  *	may be uuencoded, and sent over the network.
8  *
9  *			Paul Haeberli @ Silicon Graphics - 1989
10  *
11  *    * Modified Jan 1995 - Made parallelizable via elimination of
12  *    * global variables.
13  **********************************************************************
14  */
15 #include <stdio.h>
16 #include <string.h>
17 #include <math.h>
18 #include <stdlib.h>
19 #include <grass/gis.h>
20 #include "togif.h"
21 #define GIFGAMMA	(1.5)	/* smaller makes output image darker */
22 #define MAXCOLORS 256
23 #define CBITS    12
24 
25 typedef int (*ifunptr) (int x, int y, vgl_GIFWriter * dataPtr);
26 
27 
28 /***************************************************************************
29  * These routines interface the non-GIF data to the GIF black box (GIFENCOD)
30  ***************************************************************************
31  */
32 static int getgifpix2(int x, int y, vgl_GIFWriter * dataPtr);
33 static void getrow2(unsigned long *buffer, short *row, unsigned short width,
34 		    unsigned short rownum, unsigned short comp);
35 static void gammawarp(short *sbuf, float gam, int n, vgl_GIFWriter * dataPtr);
36 static short **makedittab(int levels, int mult, int add);
37 static int ditherrow(unsigned short *r, unsigned short *g, unsigned short *b,
38 		     short *wp, int n, int y, vgl_GIFWriter * dataPtr);
39 
40 /******************************************************************************
41  * GIF black box routines
42  ******************************************************************************
43  */
44 static void BumpPixel(vgl_GIFWriter * dataPtr);
45 static int GIFNextPixel(ifunptr getpixel, vgl_GIFWriter * dataPtr);
46 static int GIFEncode(FILE * fp, int GWidth, int GHeight, int GInterlace,
47 		     int Background, int BitsPerPixel, int Red[], int Green[],
48 		     int Blue[], ifunptr GetPixel, vgl_GIFWriter * dataPtr);
49 static void Putword(int w, FILE * fp);
50 
51 /******************************************************************************
52  * GIF compression black box routines
53  ******************************************************************************
54  */
55 static void compress(int init_bits, FILE * outfile, ifunptr ReadValue,
56 		     vgl_GIFWriter * dataPtr);
57 static void output(code_int code, vgl_GIFWriter * dataPtr);
58 static void cl_block(vgl_GIFWriter * dataPtr);
59 static void cl_hash(register count_int hsize, vgl_GIFWriter * dataPtr);
60 static void writeerr();
61 static void flush_char(vgl_GIFWriter * dataPtr);
62 static void char_out(int c, vgl_GIFWriter * dataPtr);
63 static void char_init(vgl_GIFWriter * dataPtr);
64 
65 /************************ vgl_GIFWriterBegin() ******************************/
vgl_GIFWriterBegin(void)66 vgl_GIFWriter *vgl_GIFWriterBegin(void)
67 {
68     vgl_GIFWriter *gifwriter;
69 
70     gifwriter = (vgl_GIFWriter *) G_malloc(sizeof(vgl_GIFWriter));
71     return gifwriter;
72 }
73 
74 /************************** vgl_GIFWriterEnd() ********************************/
vgl_GIFWriterEnd(vgl_GIFWriter * gifwriter)75 void vgl_GIFWriterEnd(vgl_GIFWriter * gifwriter)
76 {
77     G_free(gifwriter);
78 }
79 
80 /********************** vgl_GIFWriterWriteGIFFile() ****************************/
vgl_GIFWriterWriteGIFFile(vgl_GIFWriter * gifwriter,unsigned long * buffer,int xsize,int ysize,int bwflag,FILE * outf)81 void vgl_GIFWriterWriteGIFFile(vgl_GIFWriter * gifwriter,
82 			       unsigned long *buffer, int xsize, int ysize,
83 			       int bwflag, FILE * outf)
84 {
85     short r, g, b;
86     int i;
87     int bpp;
88     int gifcolors;
89     int rmap[MAXCOLORS];
90     int gmap[MAXCOLORS];
91     int bmap[MAXCOLORS];
92 
93     memset(gifwriter, '\0', sizeof(vgl_GIFWriter));
94     gifwriter->maxbits = CBITS;	/* user settable max # bits/code */
95     gifwriter->maxmaxcode = (code_int) 1 << CBITS;	/* should NEVER generate this code */
96     gifwriter->hsize = HSIZE;
97     gifwriter->in_count = 1;
98 
99     gifwriter->xsize = xsize;
100     gifwriter->ysize = ysize;
101     gifwriter->iscolor = !bwflag;
102     gifwriter->buffer = buffer;
103     if (gifwriter->iscolor) {
104 	gifcolors = 256;
105 	bpp = 8;
106 	for (i = 0; i < gifcolors; i++) {
107 	    r = (i >> 0) & 0x7;
108 	    g = (i >> 3) & 0x7;
109 	    b = (i >> 6) & 0x3;
110 	    rmap[i] = (255 * r) / 7;
111 	    gmap[i] = (255 * g) / 7;
112 	    bmap[i] = (255 * b) / 3;
113 	}
114     }
115     else {
116 	gifcolors = 16;
117 	bpp = 4;
118 	for (i = 0; i < gifcolors; i++) {
119 	    rmap[i] = (255 * i) / (gifcolors - 1);
120 	    gmap[i] = (255 * i) / (gifcolors - 1);
121 	    bmap[i] = (255 * i) / (gifcolors - 1);
122 	}
123     }
124 
125 
126     gifwriter->currow = -1;
127     GIFEncode(outf, xsize, ysize, 1, 0, bpp, rmap, gmap, bmap, getgifpix2,
128 	      gifwriter);
129 
130 }
131 
132 /************************** getgifpix2() ********************************/
getgifpix2(int x,int y,vgl_GIFWriter * dataPtr)133 static int getgifpix2(int x, int y, vgl_GIFWriter * dataPtr)
134 {
135     int pix;
136 
137     if (dataPtr->iscolor) {
138 	if (dataPtr->currow != y) {
139 	    getrow2(dataPtr->buffer, dataPtr->rbuf, dataPtr->xsize,
140 		    dataPtr->ysize - 1 - y, 0);
141 	    gammawarp(dataPtr->rbuf, 1.0 / GIFGAMMA, dataPtr->xsize, dataPtr);
142 	    getrow2(dataPtr->buffer, dataPtr->gbuf, dataPtr->xsize,
143 		    dataPtr->ysize - 1 - y, 1);
144 	    gammawarp(dataPtr->gbuf, 1.0 / GIFGAMMA, dataPtr->xsize, dataPtr);
145 	    getrow2(dataPtr->buffer, dataPtr->bbuf, dataPtr->xsize,
146 		    dataPtr->ysize - 1 - y, 2);
147 	    gammawarp(dataPtr->bbuf, 1.0 / GIFGAMMA, dataPtr->xsize, dataPtr);
148 	    ditherrow((unsigned short *)(dataPtr->rbuf),
149 		      (unsigned short *)(dataPtr->gbuf),
150 		      (unsigned short *)(dataPtr->bbuf), dataPtr->obuf,
151 		      dataPtr->xsize, y, dataPtr);
152 	    dataPtr->currow = y;
153 	}
154 	pix = dataPtr->obuf[x];
155     }
156     else {
157 	if (dataPtr->currow != y) {
158 	    getrow2(dataPtr->buffer, dataPtr->rbuf, dataPtr->xsize,
159 		    dataPtr->ysize - 1 - y, 0);
160 	    gammawarp(dataPtr->rbuf, 1.0 / GIFGAMMA, dataPtr->xsize, dataPtr);
161 	    ditherrow((unsigned short *)(dataPtr->rbuf),
162 		      (unsigned short *)(dataPtr->rbuf),
163 		      (unsigned short *)(dataPtr->rbuf), dataPtr->obuf,
164 		      dataPtr->xsize, y, dataPtr);
165 	    dataPtr->currow = y;
166 	}
167 	pix = dataPtr->obuf[x] & 0xf;
168     }
169     return pix;
170 }
171 
172 /************************** getrow2() ********************************/
getrow2(unsigned long * buffer,short * row,unsigned short width,unsigned short rownum,unsigned short comp)173 static void getrow2(unsigned long *buffer, short *row, unsigned short width,
174 		    unsigned short rownum, unsigned short comp)
175 {
176     unsigned short i;
177     unsigned long *ptr = buffer + width * rownum;
178 
179     switch (comp) {
180     case 0:
181 	for (i = 0; i < width; i++) {
182 	    row[i] = *ptr & 0xff;
183 	    ptr++;
184 	}
185 	break;
186     case 1:
187 	for (i = 0; i < width; i++) {
188 	    row[i] = (*ptr >> 8) & 0xff;
189 	    ptr++;
190 	}
191 	break;
192     case 2:
193 	for (i = 0; i < width; i++) {
194 	    row[i] = (*ptr >> 16) & 0xff;
195 	    ptr++;
196 	}
197 	break;
198     }
199 }
200 
201 /********************** gammawarp() ***************************/
gammawarp(short * sbuf,float gam,int n,vgl_GIFWriter * dataPtr)202 static void gammawarp(short *sbuf, float gam, int n, vgl_GIFWriter * dataPtr)
203 {
204     int i;
205     float f;
206 
207     if (gam != dataPtr->curgamma) {
208 	for (i = 0; i < 256; i++)
209 	    dataPtr->gamtab[i] = 255 * pow(i / 255.0, gam) + 0.5;
210 	dataPtr->curgamma = gam;
211     }
212     while (n--) {
213 	*sbuf = dataPtr->gamtab[*sbuf];
214 	sbuf++;
215     }
216 }
217 
218 /***************************************************************************
219  *  	dithering code follows
220  */
221 #define XSIZE	4
222 #define YSIZE	4
223 #define TOTAL		(XSIZE*YSIZE)
224 #define WRAPY(y)	((y)%YSIZE)
225 #define WRAPX(x)	((x)%XSIZE)
226 
227 static short dithmat[YSIZE][XSIZE] = {
228     0, 8, 2, 10,
229     12, 4, 14, 6,
230     3, 11, 1, 9,
231     15, 7, 13, 5,
232 };
233 
234 /************************** makedittab() ********************************/
makedittab(int levels,int mult,int add)235 static short **makedittab(int levels, int mult, int add)
236 {
237     register int val;
238     register int nshades;
239     register int i, j, k;
240     register int matval, tabval;
241     short **tab;
242 
243     nshades = XSIZE * YSIZE * (levels - 1) + 1;
244     tab = (short **)G_malloc(YSIZE * sizeof(short *));
245     for (j = 0; j < YSIZE; j++) {
246 	tab[j] = (short *)G_malloc(XSIZE * 256 * sizeof(short));
247 	for (i = 0; i < XSIZE; i++) {
248 	    matval = dithmat[i][j];
249 	    for (k = 0; k < 256; k++) {
250 		val = (nshades * k) / 255;
251 		if (val == nshades)
252 		    val = nshades - 1;
253 		if ((val % TOTAL) > matval)
254 		    tabval = (val / TOTAL) + 1;
255 		else
256 		    tabval = (val / TOTAL);
257 		tabval *= mult;
258 		tabval += add;
259 		tab[j][256 * i + k] = tabval;
260 	    }
261 	}
262     }
263     return tab;
264 }
265 
266 /************************** ditherrow() ********************************/
ditherrow(unsigned short * r,unsigned short * g,unsigned short * b,short * wp,int n,int y,vgl_GIFWriter * dataPtr)267 static int ditherrow(unsigned short *r, unsigned short *g, unsigned short *b,
268 		     short *wp, int n, int y, vgl_GIFWriter * dataPtr)
269 {
270     short *rbase;
271     short *gbase;
272     short *bbase;
273 
274     if (!dataPtr->rtab) {
275 	if (dataPtr->iscolor) {
276 	    dataPtr->rtab = makedittab(8, 1, 0);
277 	    dataPtr->gtab = makedittab(8, 8, 0);
278 	    dataPtr->btab = makedittab(4, 64, 0);
279 	}
280 	else {
281 	    dataPtr->rtab = makedittab(16, 1, 0);
282 	    dataPtr->gtab = makedittab(2, 16, 0);
283 	    dataPtr->btab = makedittab(2, 32, 0);
284 	}
285     }
286     rbase = dataPtr->rtab[WRAPY(y)];
287     gbase = dataPtr->gtab[WRAPY(y)];
288     bbase = dataPtr->btab[WRAPY(y)];
289     while (n) {
290 	if (n >= XSIZE) {
291 	    *wp++ = rbase[*r++ + 0] + gbase[*g++ + 0] + bbase[*b++ + 0];
292 	    *wp++ = rbase[*r++ + 256] + gbase[*g++ + 256] + bbase[*b++ + 256];
293 	    *wp++ = rbase[*r++ + 512] + gbase[*g++ + 512] + bbase[*b++ + 512];
294 	    *wp++ = rbase[*r++ + 768] + gbase[*g++ + 768] + bbase[*b++ + 768];
295 	    n -= XSIZE;
296 	}
297 	else {
298 	    *wp++ = rbase[*r++] + gbase[*g++] + bbase[*b++];
299 	    rbase += 256;
300 	    gbase += 256;
301 	    bbase += 256;
302 	    n--;
303 	}
304     }
305     return 1;
306 }
307 
308 
309 /*****************************************************************************
310  * SCARY GIF code follows . . . . sorry.
311  *
312  * Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
313  * Lempel-Zim compression based on "compress".
314  *
315  *****************************************************************************
316  */
317 
318 /*****************************************************************************
319  *
320  * GIFENCODE.C    - GIF Image compression interface
321  *
322  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background,
323  *            BitsPerPixel, Red, Green, Blue, GetPixel )
324  *
325  *****************************************************************************/
326 
327 
328 /************************** BumpPixel() ********************************/
329 /*
330  * Bump the 'curx' and 'cury' to point to the next pixel
331  */
BumpPixel(vgl_GIFWriter * dataPtr)332 static void BumpPixel(vgl_GIFWriter * dataPtr)
333 {
334     dataPtr->curx++;
335     if (dataPtr->curx == dataPtr->xsize) {
336 	dataPtr->curx = 0;
337 	if (!dataPtr->interlace) {
338 	    dataPtr->cury++;
339 	}
340 	else {
341 	    switch (dataPtr->pass) {
342 	    case 0:
343 		dataPtr->cury += 8;
344 		if (dataPtr->cury >= dataPtr->ysize) {
345 		    dataPtr->pass++;
346 		    dataPtr->cury = 4;
347 		}
348 		break;
349 	    case 1:
350 		dataPtr->cury += 8;
351 		if (dataPtr->cury >= dataPtr->ysize) {
352 		    dataPtr->pass++;
353 		    dataPtr->cury = 2;
354 		}
355 		break;
356 	    case 2:
357 		dataPtr->cury += 4;
358 		if (dataPtr->cury >= dataPtr->ysize) {
359 		    dataPtr->pass++;
360 		    dataPtr->cury = 1;
361 		}
362 		break;
363 	    case 3:
364 		dataPtr->cury += 2;
365 		break;
366 	    }
367 	}
368     }
369 }
370 
371 /************************** GIFNextPixel() ********************************/
372 /*
373  * Return the next pixel from the image
374  */
GIFNextPixel(ifunptr getpixel,vgl_GIFWriter * dataPtr)375 static int GIFNextPixel(ifunptr getpixel, vgl_GIFWriter * dataPtr)
376 {
377     int r;
378 
379     if (dataPtr->countDown == 0)
380 	return EOF;
381     dataPtr->countDown--;
382     r = (*getpixel) (dataPtr->curx, dataPtr->cury, dataPtr);
383     BumpPixel(dataPtr);
384     return r;
385 }
386 
387 /************************** GIFEncode () ********************************/
388 /*
389  * public GIFEncode
390  */
GIFEncode(FILE * fp,int GWidth,int GHeight,int GInterlace,int Background,int BitsPerPixel,int Red[],int Green[],int Blue[],ifunptr GetPixel,vgl_GIFWriter * dataPtr)391 static int GIFEncode(FILE * fp, int GWidth, int GHeight, int GInterlace,
392 		     int Background, int BitsPerPixel, int Red[], int Green[],
393 		     int Blue[], ifunptr GetPixel, vgl_GIFWriter * dataPtr)
394 {
395     int B;
396     int RWidth, RHeight;
397     int LeftOfs, TopOfs;
398     int Resolution;
399     int ColorMapSize;
400     int InitCodeSize;
401     int i;
402 
403     dataPtr->cur_bits = 0;
404 
405     dataPtr->interlace = GInterlace;
406     ColorMapSize = 1 << BitsPerPixel;
407     RWidth = dataPtr->xsize;
408     RHeight = dataPtr->ysize;
409     LeftOfs = TopOfs = 0;
410     Resolution = BitsPerPixel;
411 
412     dataPtr->countDown = (long)(dataPtr->xsize) * (long)(dataPtr->ysize);
413     dataPtr->pass = 0;
414     if (BitsPerPixel <= 1)
415 	InitCodeSize = 2;
416     else
417 	InitCodeSize = BitsPerPixel;
418     dataPtr->curx = dataPtr->cury = 0;
419     fwrite("GIF87a", 1, 6, fp);
420     Putword(RWidth, fp);
421     Putword(RHeight, fp);
422     B = 0x80;			/* Yes, there is a color map */
423     B |= (Resolution - 1) << 5;
424     B |= (BitsPerPixel - 1);
425     fputc(B, fp);
426     fputc(Background, fp);
427     fputc(0, fp);
428     for (i = 0; i < ColorMapSize; i++) {
429 	fputc(Red[i], fp);
430 	fputc(Green[i], fp);
431 	fputc(Blue[i], fp);
432     }
433     fputc(',', fp);
434     Putword(LeftOfs, fp);
435     Putword(TopOfs, fp);
436     Putword(dataPtr->xsize, fp);
437     Putword(dataPtr->ysize, fp);
438     if (dataPtr->interlace)
439 	fputc(0x40, fp);
440     else
441 	fputc(0x00, fp);
442     fputc(InitCodeSize, fp);
443     compress(InitCodeSize + 1, fp, GetPixel, dataPtr);
444     fputc(0, fp);
445     fputc(';', fp);
446     fclose(fp);
447     return 1;
448 }
449 
450 /************************** Putword () ********************************/
451 /*
452  * Write out a word to the GIF file
453  */
Putword(int w,FILE * fp)454 static void Putword(int w, FILE * fp)
455 {
456 
457     fputc(w & 0xff, fp);
458     fputc((w / 256) & 0xff, fp);
459 }
460 
461 
462 /***************************************************************************
463  *
464  *  GIFCOMPR.C       - GIF Image compression routines
465  *
466  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
467  *  David Rowley (mgardi@watdcsu.waterloo.edu)
468  *
469  ***************************************************************************/
470 
471 
472 /*
473  *
474  * GIF Image compression - modified 'compress'
475  *
476  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
477  *
478  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
479  *              Jim McKie               (decvax!mcvax!jim)
480  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
481  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
482  *              James A. Woods          (decvax!ihnp4!ames!jaw)
483  *              Joe Orost               (decvax!vax135!petsd!joe)
484  *
485  */
486 #include <ctype.h>
487 #include <grass/gis.h>
488 
489 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
490 
491 # define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
492 
493 #define HashTabOf(i)    dataPtr->htab[i]
494 #define CodeTabOf(i)    dataPtr->codetab[i]
495 
496 
497 /*
498  * To save much memory, we overlay the table used by compress() with those
499  * used by decompress().  The tab_prefix table is the same size and type
500  * as the codetab.  The tab_suffix table needs 2**CBITS characters.  We
501  * get this from the beginning of htab.  The output stack uses the rest
502  * of htab, and contains characters.  There is plenty of room for any
503  * possible stack (stack used to be 8000 characters).
504  */
505 #define tab_prefixof(i) CodeTabOf(i)
506 #define tab_suffixof(i)        ((char_type *)(dataPtr->htab))[i]
507 #define de_stack               ((char_type *)&tab_suffixof((code_int)1<<CBITS))
508 
509 
510 
511 /************************** compress () ********************************
512  * compress stdin to stdout
513  *
514  * Algorithm:  use open addressing double hashing (no chaining) on the
515  * prefix code / next character combination.  We do a variant of Knuth's
516  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
517  * secondary probe.  Here, the modular division first probe is gives way
518  * to a faster exclusive-or manipulation.  Also do block compression with
519  * an adaptive reset, whereby the code table is cleared when the compression
520  * ratio decreases, but after the table fills.  The variable-length output
521  * codes are re-sized at this point, and a special CLEAR code is generated
522  * for the decompressor.  Late addition:  construct the table according to
523  * file size for noticeable speed improvement on small files.  Please direct
524  * questions about this implementation to ames!jaw.
525  */
compress(int init_bits,FILE * outfile,ifunptr ReadValue,vgl_GIFWriter * dataPtr)526 static void compress(int init_bits, FILE * outfile, ifunptr ReadValue,
527 		     vgl_GIFWriter * dataPtr)
528 {
529     register long fcode;
530     register code_int i = 0;
531     register int c;
532     register code_int ent;
533     register code_int disp;
534     register code_int hsize_reg;
535     register int hshift;
536 
537     /*
538      * Set up the globals:  g_init_bits - initial number of bits
539      *                      g_outfile   - pointer to output file
540      */
541     dataPtr->g_init_bits = init_bits;
542     dataPtr->g_outfile = outfile;
543     /*
544      * Set up the necessary values
545      */
546     dataPtr->offset = 0;
547     dataPtr->out_count = 0;
548     dataPtr->clear_flg = 0;
549     dataPtr->in_count = 1;
550     dataPtr->maxcode = MAXCODE(dataPtr->n_bits = dataPtr->g_init_bits);
551     dataPtr->clearCode = (1 << (init_bits - 1));
552     dataPtr->EOFCode = dataPtr->clearCode + 1;
553     dataPtr->free_ent = dataPtr->clearCode + 2;
554     char_init(dataPtr);
555     ent = GIFNextPixel(ReadValue, dataPtr);
556     hshift = 0;
557     for (fcode = (long)(dataPtr->hsize); fcode < 65536L; fcode *= 2L)
558 	hshift++;
559     hshift = 8 - hshift;	/* set hash code range bound */
560     hsize_reg = dataPtr->hsize;
561     cl_hash((count_int) hsize_reg, dataPtr);	/* clear hash table */
562     output((code_int) (dataPtr->clearCode), dataPtr);
563     while ((c = GIFNextPixel(ReadValue, dataPtr)) != EOF) {
564 	dataPtr->in_count++;
565 	fcode = (long)(((long)c << dataPtr->maxbits) + ent);
566 	/* i = (((code_int)c << hshift) ~ ent);  */
567 	i = (((code_int) c << hshift) ^ ent);	/* xor hashing */
568 	if (HashTabOf(i) == fcode) {
569 	    ent = CodeTabOf(i);
570 	    continue;
571 	}
572 	else if ((long)HashTabOf(i) < 0)	/* empty slot */
573 	    goto nomatch;
574 	disp = hsize_reg - i;	/* secondary hash (after G. Knott) */
575 	if (i == 0)
576 	    disp = 1;
577       probe:
578 	if ((i -= disp) < 0)
579 	    i += hsize_reg;
580 	if (HashTabOf(i) == fcode) {
581 	    ent = CodeTabOf(i);
582 	    continue;
583 	}
584 	if ((long)HashTabOf(i) > 0)
585 	    goto probe;
586       nomatch:
587 	output((code_int) ent, dataPtr);
588 	dataPtr->out_count++;
589 	ent = c;
590 	if (dataPtr->free_ent < dataPtr->maxmaxcode) {
591 	    CodeTabOf(i) = dataPtr->free_ent++;	/* code -> hashtable */
592 	    HashTabOf(i) = fcode;
593 	}
594 	else
595 	    cl_block(dataPtr);
596     }
597     /*
598      * Put out the final code.
599      */
600     output((code_int) ent, dataPtr);
601     dataPtr->out_count++;
602     output((code_int) (dataPtr->EOFCode), dataPtr);
603     return;
604 }
605 
606 /*****************************************************************
607  * TAG( output )
608  *
609  * Output the given code.
610  * Inputs:
611  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
612  *              that n_bits =< (long)wordsize - 1.
613  * Outputs:
614  *      Outputs code to the file.
615  * Assumptions:
616  *      Chars are 8 bits long.
617  * Algorithm:
618  *      Maintain a CBITS character long buffer (so that 8 codes will
619  * fit in it exactly).  Use the VAX insv instruction to insert each
620  * code in turn.  When the buffer fills up empty it and start over.
621  */
622 
623 static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
624     0x001F, 0x003F, 0x007F, 0x00FF,
625     0x01FF, 0x03FF, 0x07FF, 0x0FFF,
626     0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
627 };
628 
output(code_int code,vgl_GIFWriter * dataPtr)629 static void output(code_int code, vgl_GIFWriter * dataPtr)
630 {
631     dataPtr->cur_accum &= masks[dataPtr->cur_bits];
632     if (dataPtr->cur_bits > 0)
633 	dataPtr->cur_accum |= ((long)code << dataPtr->cur_bits);
634     else
635 	dataPtr->cur_accum = code;
636     dataPtr->cur_bits += dataPtr->n_bits;
637     while (dataPtr->cur_bits >= 8) {
638 	char_out((unsigned int)(dataPtr->cur_accum & 0xff), dataPtr);
639 	dataPtr->cur_accum >>= 8;
640 	dataPtr->cur_bits -= 8;
641     }
642 
643     /*
644      * If the next entry is going to be too big for the code size,
645      * then increase it, if possible.
646      */
647     if (dataPtr->free_ent > dataPtr->maxcode || dataPtr->clear_flg) {
648 	if (dataPtr->clear_flg) {
649 	    dataPtr->maxcode = MAXCODE(dataPtr->n_bits =
650 				       dataPtr->g_init_bits);
651 	    dataPtr->clear_flg = 0;
652 	}
653 	else {
654 	    dataPtr->n_bits++;
655 	    if (dataPtr->n_bits == dataPtr->maxbits)
656 		dataPtr->maxcode = dataPtr->maxmaxcode;
657 	    else
658 		dataPtr->maxcode = MAXCODE(dataPtr->n_bits);
659 	}
660     }
661     if (code == dataPtr->EOFCode) {
662 	/*
663 	 * At EOF, write the rest of the buffer.
664 	 */
665 	while (dataPtr->cur_bits > 0) {
666 	    char_out((unsigned int)(dataPtr->cur_accum & 0xff), dataPtr);
667 	    dataPtr->cur_accum >>= 8;
668 	    dataPtr->cur_bits -= 8;
669 	}
670 	flush_char(dataPtr);
671 	fflush(dataPtr->g_outfile);
672 	if (ferror(dataPtr->g_outfile))
673 	    writeerr();
674     }
675 }
676 
677 /********************** cl_block() ***************************/
678 /*
679  * table clear for block compress
680  */
cl_block(vgl_GIFWriter * dataPtr)681 static void cl_block(vgl_GIFWriter * dataPtr)
682 {
683     cl_hash((count_int) (dataPtr->hsize), dataPtr);
684     dataPtr->free_ent = dataPtr->clearCode + 2;
685     dataPtr->clear_flg = 1;
686     output((code_int) (dataPtr->clearCode), dataPtr);
687 }
688 
689 /********************** cl_hash() ***************************/
690 /* reset code table */
cl_hash(register count_int hsize,vgl_GIFWriter * dataPtr)691 static void cl_hash(register count_int hsize, vgl_GIFWriter * dataPtr)
692 {
693     register count_int *htab_p;
694     register long i;
695     register long m1 = -1;
696 
697     htab_p = dataPtr->htab + hsize;
698 
699     i = hsize - 16;
700     do {			/* might use Sys V memset(3) here */
701 	*(htab_p - 16) = m1;
702 	*(htab_p - 15) = m1;
703 	*(htab_p - 14) = m1;
704 	*(htab_p - 13) = m1;
705 	*(htab_p - 12) = m1;
706 	*(htab_p - 11) = m1;
707 	*(htab_p - 10) = m1;
708 	*(htab_p - 9) = m1;
709 	*(htab_p - 8) = m1;
710 	*(htab_p - 7) = m1;
711 	*(htab_p - 6) = m1;
712 	*(htab_p - 5) = m1;
713 	*(htab_p - 4) = m1;
714 	*(htab_p - 3) = m1;
715 	*(htab_p - 2) = m1;
716 	*(htab_p - 1) = m1;
717 	htab_p -= 16;
718     } while ((i -= 16) >= 0);
719     for (i += 16; i > 0; i--)
720 	*--htab_p = m1;
721 }
722 
723 /********************** writeerr() ***************************/
writeerr()724 static void writeerr()
725 {
726 }
727 
728 /******************************************************************************
729  *
730  * GIF Specific routines used by compression stuff
731  *
732  ******************************************************************************/
733 
734 /********************** char_init() ***************************/
735 /*
736  * Set up the 'byte output' routine
737  */
char_init(vgl_GIFWriter * dataPtr)738 static void char_init(vgl_GIFWriter * dataPtr)
739 {
740     dataPtr->a_count = 0;
741 }
742 
743 /*
744  * Define the storage for the packet accumulator
745  */
746 
747 /********************** char_out() ***************************/
748 /*
749  * Add a character to the end of the current packet, and if it is 254
750  * characters, flush the packet to disk.
751  */
char_out(int c,vgl_GIFWriter * dataPtr)752 static void char_out(int c, vgl_GIFWriter * dataPtr)
753 {
754     dataPtr->accum[dataPtr->a_count++] = c;
755     if (dataPtr->a_count >= 254)
756 	flush_char(dataPtr);
757 }
758 
759 /********************** flush_char() ***************************/
760 /*
761  * Flush the packet to disk, and reset the accumulator
762  */
flush_char(vgl_GIFWriter * dataPtr)763 static void flush_char(vgl_GIFWriter * dataPtr)
764 {
765     if (dataPtr->a_count > 0) {
766 	fputc(dataPtr->a_count, dataPtr->g_outfile);
767 	fwrite(dataPtr->accum, 1, dataPtr->a_count, dataPtr->g_outfile);
768 	dataPtr->a_count = 0;
769     }
770 }
771 
772 /*
773    main(int argc,char *argv[] )
774    {
775    FILE *of;
776    int xsize, ysize,bwflag;
777    unsigned long *buffer;
778    int i;
779    int j;
780    vgl_GIFWriter *gifwriter;
781 
782    if(argc<3) {
783    fprintf(stderr,"usage: togif image.rgb image.gif\n");
784    exit(1);
785    }
786    gifwriter = vgl_GIFWriterBegin();
787 
788    xsize = ysize = 200;
789    buffer = (unsigned long *)G_malloc ((xsize)*(ysize) * sizeof(unsigned long));
790    for(i = 0; i < ysize; i++)
791    {
792    for(j = 0; j < xsize; j++)
793    {
794 
795 
796    buffer[j + i * xsize] =
797    i | j << 8 | (0xff<<24);
798    }
799 
800    }
801    bwflag = 0;
802 
803    of = fopen(argv[2],"w");
804    if(!of) {
805    fprintf(stderr,"togif: can't open output image [%s]\n",argv[2]);
806    exit(1);
807    }
808    vgl_GIFWriterWriteGIFFile(gifwriter,buffer,xsize,ysize,bwflag,of);
809    vgl_GIFWriterEnd(gifwriter);
810    fclose(of);
811    exit(0);
812    }
813  */
814