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