1 /*
2  * xvgifwr.c  -  handles writing of GIF files.  based on flgife.c and
3  *               flgifc.c from the FBM Library, by Michael Maudlin
4  *
5  * Contains:
6  *   WriteGIF(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
7  *            comment)
8  *
9  * Note: slightly brain-damaged, in that it'll only write non-interlaced
10  *       GIF files (in the interests of speed, or something)
11  *
12  */
13 
14 
15 
16 /*****************************************************************
17  * Portions of this code Copyright (C) 1989 by Michael Mauldin.
18  * Permission is granted to use this file in whole or in
19  * part for any purpose, educational, recreational or commercial,
20  * provided that this copyright notice is retained unchanged.
21  * This software is available to all free of charge by anonymous
22  * FTP and in the UUNET archives.
23  *
24  *
25  * Authors:  Michael Mauldin (mlm@cs.cmu.edu)
26  *           David Rowley (mgardi@watdcsu.waterloo.edu)
27  *
28  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
29  *
30  *	Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
31  *	Jim McKie               (decvax!mcvax!jim)
32  *	Steve Davies            (decvax!vax135!petsd!peora!srd)
33  *	Ken Turkowski           (decvax!decwrl!turtlevax!ken)
34  *	James A. Woods          (decvax!ihnp4!ames!jaw)
35  *	Joe Orost               (decvax!vax135!petsd!joe)
36  *****************************************************************/
37 
38 
39 #include "xv.h"
40 
41 typedef long int        count_int;
42 
43 static int  Width, Height;
44 static int  curx, cury;
45 static long CountDown;
46 static int  Interlace;
47 
48 static void putword     PARM((int, FILE *));
49 static void compress    PARM((int, FILE *, byte *, int));
50 static void output      PARM((int));
51 static void cl_block    PARM((void));
52 static void cl_hash     PARM((count_int));
53 static void char_init   PARM((void));
54 static void char_out    PARM((int));
55 static void flush_char  PARM((void));
56 
57 
58 static byte pc2nc[256];
59 
60 
61 /*************************************************************/
WriteGIF(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,comment)62 int WriteGIF(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
63 	     comment)
64      FILE *fp;
65      byte *pic;
66      int   ptype, w,h;
67      byte *rmap, *gmap, *bmap;
68      int   numcols, colorstyle;
69      char *comment;
70 {
71   int   RWidth, RHeight;
72   int   LeftOfs, TopOfs;
73   int   ColorMapSize, InitCodeSize, Background, BitsPerPixel;
74   int   i,j,nc;
75   byte *pic8;
76   byte  rtemp[256],gtemp[256],btemp[256];  /* for 24-bit to 8-bit conversion */
77   byte  r1[256],g1[256],b1[256];           /* for duplicated-color remapping */
78 
79   if (ptype == PIC24) {  /* have to quantize down to 8 bits */
80     pic8 = Conv24to8(pic, w, h, 256, rtemp,gtemp,btemp);
81     if (!pic8) FatalError("Unable to malloc in WriteGIF()");
82     rmap = rtemp;  gmap = gtemp;  bmap = btemp;  numcols=256;
83   }
84   else pic8 = pic;
85 
86 
87 
88   Interlace = 0;
89   Background = 0;
90 
91 
92   for (i=0; i<256; i++) { pc2nc[i] = r1[i] = g1[i] = b1[i] = 0; }
93 
94   /* compute number of unique colors */
95   nc = 0;
96 
97   for (i=0; i<numcols; i++) {
98     /* see if color #i is already used */
99     for (j=0; j<i; j++) {
100       if (rmap[i] == rmap[j] && gmap[i] == gmap[j] &&
101 	  bmap[i] == bmap[j]) break;
102     }
103 
104     if (j==i) {  /* wasn't found */
105       pc2nc[i] = nc;
106       r1[nc] = rmap[i];
107       g1[nc] = gmap[i];
108       b1[nc] = bmap[i];
109       nc++;
110     }
111     else pc2nc[i] = pc2nc[j];
112   }
113 
114 
115   /* figure out 'BitsPerPixel' */
116   for (i=1; i<8; i++)
117     if ( (1<<i) >= nc) break;
118 
119   BitsPerPixel = i;
120 
121   ColorMapSize = 1 << BitsPerPixel;
122 
123   RWidth  = Width  = w;
124   RHeight = Height = h;
125   LeftOfs = TopOfs = 0;
126 
127   CountDown = w * h;    /* # of pixels we'll be doing */
128 
129   if (BitsPerPixel <= 1) InitCodeSize = 2;
130                     else InitCodeSize = BitsPerPixel;
131 
132   curx = cury = 0;
133 
134   if (!fp) {
135     fprintf(stderr,  "WriteGIF: file not open for writing\n" );
136     if (ptype == PIC24) free(pic8);
137     return (1);
138   }
139 
140   if (DEBUG)
141     fprintf(stderr,"WrGIF: pic=%lx, w,h=%dx%d, numcols=%d, Bits%d,Cmap=%d\n",
142 	    (u_long) pic8, w,h,numcols,BitsPerPixel,ColorMapSize);
143 
144   if (comment && strlen(comment) > (size_t) 0)
145     fwrite("GIF89a", (size_t) 1, (size_t) 6, fp);    /* the GIF magic number */
146   else
147     fwrite("GIF87a", (size_t) 1, (size_t) 6, fp);    /* the GIF magic number */
148 
149   putword(RWidth, fp);           /* screen descriptor */
150   putword(RHeight, fp);
151 
152   i = 0x80;	                 /* Yes, there is a color map */
153   i |= (8-1)<<4;                 /* OR in the color resolution (hardwired 8) */
154   i |= (BitsPerPixel - 1);       /* OR in the # of bits per pixel */
155   fputc(i,fp);
156 
157   fputc(Background, fp);         /* background color */
158 
159   fputc(0, fp);                  /* future expansion byte */
160 
161 
162   if (colorstyle == 1) {         /* greyscale */
163     for (i=0; i<ColorMapSize; i++) {
164       j = MONO(r1[i], g1[i], b1[i]);
165       fputc(j, fp);
166       fputc(j, fp);
167       fputc(j, fp);
168     }
169   }
170   else {
171     for (i=0; i<ColorMapSize; i++) {       /* write out Global colormap */
172       fputc(r1[i], fp);
173       fputc(g1[i], fp);
174       fputc(b1[i], fp);
175     }
176   }
177 
178   if (comment && strlen(comment) > (size_t) 0) {   /* write comment blocks */
179     char *sp;
180     int   i, blen;
181 
182     fputc(0x21, fp);     /* EXTENSION block */
183     fputc(0xFE, fp);     /* comment extension */
184 
185     sp = comment;
186     while ( (blen=strlen(sp)) > 0) {
187       if (blen>255) blen = 255;
188       fputc(blen, fp);
189       for (i=0; i<blen; i++, sp++) fputc(*sp, fp);
190     }
191     fputc(0, fp);    /* zero-length data subblock to end extension */
192   }
193 
194 
195   fputc( ',', fp );              /* image separator */
196 
197   /* Write the Image header */
198   putword(LeftOfs, fp);
199   putword(TopOfs,  fp);
200   putword(Width,   fp);
201   putword(Height,  fp);
202   if (Interlace) fputc(0x40, fp);   /* Use Global Colormap, maybe Interlace */
203             else fputc(0x00, fp);
204 
205   fputc(InitCodeSize, fp);
206   compress(InitCodeSize+1, fp, pic8, w*h);
207 
208   fputc(0,fp);                      /* Write out a Zero-length packet (EOF) */
209   fputc(';',fp);                    /* Write GIF file terminator */
210 
211   if (ptype == PIC24) free(pic8);
212 
213   if (ferror(fp)) return -1;
214   return (0);
215 }
216 
217 
218 
219 
220 /******************************/
putword(w,fp)221 static void putword(w, fp)
222 int w;
223 FILE *fp;
224 {
225   /* writes a 16-bit integer in GIF order (LSB first) */
226   fputc(w & 0xff, fp);
227   fputc((w>>8)&0xff, fp);
228 }
229 
230 
231 
232 
233 /***********************************************************************/
234 
235 
236 static unsigned long cur_accum = 0;
237 static int           cur_bits = 0;
238 
239 
240 
241 
242 #define min(a,b)        ((a>b) ? b : a)
243 
244 #define XV_BITS	12    /* BITS was already defined on some systems */
245 #define MSDOS	1
246 
247 #define HSIZE  5003            /* 80% occupancy */
248 
249 typedef unsigned char   char_type;
250 
251 
252 static int n_bits;                    /* number of bits/code */
253 static int maxbits = XV_BITS;         /* user settable max # bits/code */
254 static int maxcode;                   /* maximum code, given n_bits */
255 static int maxmaxcode = 1 << XV_BITS; /* NEVER generate this */
256 
257 #define MAXCODE(n_bits)     ( (1 << (n_bits)) - 1)
258 
259 static  count_int      htab [HSIZE];
260 static  unsigned short codetab [HSIZE];
261 #define HashTabOf(i)   htab[i]
262 #define CodeTabOf(i)   codetab[i]
263 
264 static int hsize = HSIZE;            /* for dynamic table sizing */
265 
266 /*
267  * To save much memory, we overlay the table used by compress() with those
268  * used by decompress().  The tab_prefix table is the same size and type
269  * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
270  * get this from the beginning of htab.  The output stack uses the rest
271  * of htab, and contains characters.  There is plenty of room for any
272  * possible stack (stack used to be 8000 characters).
273  */
274 
275 #define tab_prefixof(i) CodeTabOf(i)
276 #define tab_suffixof(i)        ((char_type *)(htab))[i]
277 #define de_stack               ((char_type *)&tab_suffixof(1<<XV_BITS))
278 
279 static int free_ent = 0;                  /* first unused entry */
280 
281 /*
282  * block compression parameters -- after all codes are used up,
283  * and compression rate changes, start over.
284  */
285 static int clear_flg = 0;
286 
287 static long int in_count = 1;            /* length of input */
288 static long int out_count = 0;           /* # of codes output (for debugging) */
289 
290 /*
291  * compress stdin to stdout
292  *
293  * Algorithm:  use open addressing double hashing (no chaining) on the
294  * prefix code / next character combination.  We do a variant of Knuth's
295  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
296  * secondary probe.  Here, the modular division first probe is gives way
297  * to a faster exclusive-or manipulation.  Also do block compression with
298  * an adaptive reset, whereby the code table is cleared when the compression
299  * ratio decreases, but after the table fills.  The variable-length output
300  * codes are re-sized at this point, and a special CLEAR code is generated
301  * for the decompressor.  Late addition:  construct the table according to
302  * file size for noticeable speed improvement on small files.  Please direct
303  * questions about this implementation to ames!jaw.
304  */
305 
306 static int g_init_bits;
307 static FILE *g_outfile;
308 
309 static int ClearCode;
310 static int EOFCode;
311 
312 
313 /********************************************************/
compress(init_bits,outfile,data,len)314 static void compress(init_bits, outfile, data, len)
315 int   init_bits;
316 FILE *outfile;
317 byte *data;
318 int   len;
319 {
320   register long fcode;
321   register int i = 0;
322   register int c;
323   register int ent;
324   register int disp;
325   register int hsize_reg;
326   register int hshift;
327 
328   /*
329    * Set up the globals:  g_init_bits - initial number of bits
330    *                      g_outfile   - pointer to output file
331    */
332   g_init_bits = init_bits;
333   g_outfile   = outfile;
334 
335   /* initialize 'compress' globals */
336   maxbits = XV_BITS;
337   maxmaxcode = 1<<XV_BITS;
338   xvbzero((char *) htab,    sizeof(htab));
339   xvbzero((char *) codetab, sizeof(codetab));
340   hsize = HSIZE;
341   free_ent = 0;
342   clear_flg = 0;
343   in_count = 1;
344   out_count = 0;
345   cur_accum = 0;
346   cur_bits = 0;
347 
348 
349   /*
350    * Set up the necessary values
351    */
352   out_count = 0;
353   clear_flg = 0;
354   in_count = 1;
355   maxcode = MAXCODE(n_bits = g_init_bits);
356 
357   ClearCode = (1 << (init_bits - 1));
358   EOFCode = ClearCode + 1;
359   free_ent = ClearCode + 2;
360 
361   char_init();
362   ent = pc2nc[*data++];  len--;
363 
364   hshift = 0;
365   for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
366     hshift++;
367   hshift = 8 - hshift;                /* set hash code range bound */
368 
369   hsize_reg = hsize;
370   cl_hash( (count_int) hsize_reg);            /* clear hash table */
371 
372   output(ClearCode);
373 
374   while (len) {
375     c = pc2nc[*data++];  len--;
376     in_count++;
377 
378     fcode = (long) ( ( (long) c << maxbits) + ent);
379     i = (((int) c << hshift) ^ ent);    /* xor hashing */
380 
381     if ( HashTabOf (i) == fcode ) {
382       ent = CodeTabOf (i);
383       continue;
384     }
385 
386     else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
387       goto nomatch;
388 
389     disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
390     if ( i == 0 )
391       disp = 1;
392 
393 probe:
394     if ( (i -= disp) < 0 )
395       i += hsize_reg;
396 
397     if ( HashTabOf (i) == fcode ) {
398       ent = CodeTabOf (i);
399       continue;
400     }
401 
402     if ( (long)HashTabOf (i) >= 0 )
403       goto probe;
404 
405 nomatch:
406     output(ent);
407     out_count++;
408     ent = c;
409 
410     if ( free_ent < maxmaxcode ) {
411       CodeTabOf (i) = free_ent++; /* code -> hashtable */
412       HashTabOf (i) = fcode;
413     }
414     else
415       cl_block();
416   }
417 
418   /* Put out the final code */
419   output(ent);
420   out_count++;
421   output(EOFCode);
422 }
423 
424 
425 /*****************************************************************
426  * TAG( output )
427  *
428  * Output the given code.
429  * Inputs:
430  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
431  *              that n_bits =< (long)wordsize - 1.
432  * Outputs:
433  *      Outputs code to the file.
434  * Assumptions:
435  *      Chars are 8 bits long.
436  * Algorithm:
437  *      Maintain a BITS character long buffer (so that 8 codes will
438  * fit in it exactly).  Use the VAX insv instruction to insert each
439  * code in turn.  When the buffer fills up empty it and start over.
440  */
441 
442 static
443 unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
444                                   0x001F, 0x003F, 0x007F, 0x00FF,
445                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
446                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
447 
output(code)448 static void output(code)
449 int code;
450 {
451   cur_accum &= masks[cur_bits];
452 
453   if (cur_bits > 0)
454     cur_accum |= ((long)code << cur_bits);
455   else
456     cur_accum = code;
457 
458   cur_bits += n_bits;
459 
460   while( cur_bits >= 8 ) {
461     char_out( (int) (cur_accum & 0xff) );
462     cur_accum >>= 8;
463     cur_bits -= 8;
464   }
465 
466   /*
467    * If the next entry is going to be too big for the code size,
468    * then increase it, if possible.
469    */
470 
471   if (free_ent > maxcode || clear_flg) {
472 
473     if( clear_flg ) {
474       maxcode = MAXCODE (n_bits = g_init_bits);
475       clear_flg = 0;
476     }
477     else {
478       n_bits++;
479       if ( n_bits == maxbits )
480 	maxcode = maxmaxcode;
481       else
482 	maxcode = MAXCODE(n_bits);
483     }
484   }
485 
486   if( code == EOFCode ) {
487     /* At EOF, write the rest of the buffer */
488     while( cur_bits > 0 ) {
489       char_out( (int)(cur_accum & 0xff) );
490       cur_accum >>= 8;
491       cur_bits -= 8;
492     }
493 
494     flush_char();
495 
496     fflush( g_outfile );
497 
498 #ifdef FOO
499     if( ferror( g_outfile ) )
500       FatalError("unable to write GIF file");
501 #endif
502   }
503 }
504 
505 
506 /********************************/
cl_block()507 static void cl_block ()             /* table clear for block compress */
508 {
509   /* Clear out the hash table */
510 
511   cl_hash ( (count_int) hsize );
512   free_ent = ClearCode + 2;
513   clear_flg = 1;
514 
515   output(ClearCode);
516 }
517 
518 
519 /********************************/
cl_hash(hsize)520 static void cl_hash(hsize)          /* reset code table */
521 register count_int hsize;
522 {
523   register count_int *htab_p = htab+hsize;
524   register long i;
525   register long m1 = -1;
526 
527   i = hsize - 16;
528   do {                            /* might use Sys V memset(3) here */
529     *(htab_p-16) = m1;
530     *(htab_p-15) = m1;
531     *(htab_p-14) = m1;
532     *(htab_p-13) = m1;
533     *(htab_p-12) = m1;
534     *(htab_p-11) = m1;
535     *(htab_p-10) = m1;
536     *(htab_p-9) = m1;
537     *(htab_p-8) = m1;
538     *(htab_p-7) = m1;
539     *(htab_p-6) = m1;
540     *(htab_p-5) = m1;
541     *(htab_p-4) = m1;
542     *(htab_p-3) = m1;
543     *(htab_p-2) = m1;
544     *(htab_p-1) = m1;
545     htab_p -= 16;
546   } while ((i -= 16) >= 0);
547 
548   for ( i += 16; i > 0; i-- )
549     *--htab_p = m1;
550 }
551 
552 
553 /******************************************************************************
554  *
555  * GIF Specific routines
556  *
557  ******************************************************************************/
558 
559 /*
560  * Number of characters so far in this 'packet'
561  */
562 static int a_count;
563 
564 /*
565  * Set up the 'byte output' routine
566  */
char_init()567 static void char_init()
568 {
569 	a_count = 0;
570 }
571 
572 /*
573  * Define the storage for the packet accumulator
574  */
575 static char accum[ 256 ];
576 
577 /*
578  * Add a character to the end of the current packet, and if it is 254
579  * characters, flush the packet to disk.
580  */
char_out(c)581 static void char_out(c)
582 int c;
583 {
584   accum[ a_count++ ] = c;
585   if( a_count >= 254 )
586     flush_char();
587 }
588 
589 /*
590  * Flush the packet to disk, and reset the accumulator
591  */
flush_char()592 static void flush_char()
593 {
594   if( a_count > 0 ) {
595     fputc(a_count, g_outfile );
596     fwrite(accum, (size_t) 1, (size_t) a_count, g_outfile );
597     a_count = 0;
598   }
599 }
600