1 /*
2 / gaiagraphics_gif.c
3 /
4 / GIF auxiliary helpers
5 /
6 / version 1.0, 2010 July 20
7 /
8 / Author: Sandro Furieri a.furieri@lqt.it
9 /
10 / Copyright (C) 2010  Alessandro Furieri
11 /
12 /    This program is free software: you can redistribute it and/or modify
13 /    it under the terms of the GNU Lesser General Public License as published by
14 /    the Free Software Foundation, either version 3 of the License, or
15 /    (at your option) any later version.
16 /
17 /    This program is distributed in the hope that it will be useful,
18 /    but WITHOUT ANY WARRANTY; without even the implied warranty of
19 /    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 /    GNU Lesser General Public License for more details.
21 /
22 /    You should have received a copy of the GNU Lesser General Public License
23 /    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 /
25 */
26 
27 #include <stdio.h>
28 #include <math.h>
29 #include <string.h>
30 #include <stdlib.h>
31 
32 #include "gaiagraphics.h"
33 #include "gaiagraphics_internals.h"
34 
35 /*
36 /
37 / DISCLAIMER:
38 / all the following code merely is an 'ad hoc' adaption
39 / deriving from the original GD lib code
40 / which in turn is based on he following:
41 /
42 ** Code drawn from ppmtogif.c, from the pbmplus package
43 **
44 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
45 ** Lempel-Zim compression based on "compress".
46 **
47 ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
48 **
49 ** Copyright (C) 1989 by Jef Poskanzer.
50 **
51 ** Permission to use, copy, modify, and distribute this software and its
52 ** documentation for any purpose and without fee is hereby granted, provided
53 ** that the above copyright notice appear in all copies and that both that
54 ** copyright notice and this permission notice appear in supporting
55 ** documentation.  This software is provided "as is" without express or
56 ** implied warranty.
57 **
58 ** The Graphics Interchange Format(c) is the Copyright property of
59 ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
60 ** CompuServe Incorporated.
61 /
62 */
63 
64 typedef int code_int;
65 
66 #ifdef SIGNED_COMPARE_SLOW
67 typedef unsigned long int count_int;
68 typedef unsigned short int count_short;
69 #else /*SIGNED_COMPARE_SLOW */
70 typedef long int count_int;
71 #endif /*SIGNED_COMPARE_SLOW */
72 
73 #define GIFBITS    12
74 
75 #define maxbits GIFBITS
76 
77 #define maxmaxcode ((code_int)1 << GIFBITS)
78 
79 #define HSIZE  5003
80 #define hsize HSIZE
81 
82 #ifdef COMPATIBLE
83 #define MAXCODE(n_bits)        ((code_int) 1 << (n_bits) - 1)
84 #else /*COMPATIBLE*/
85 #define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
86 #endif /*COMPATIBLE*/
87 #define HashTabOf(i)       ctx->htab[i]
88 #define CodeTabOf(i)    ctx->codetab[i]
89     typedef struct
90 {
91     int Width, Height;
92     int curx, cury;
93     long CountDown;
94     int Pass;
95     int Interlace;
96     int n_bits;
97     code_int maxcode;
98     count_int htab[HSIZE];
99     unsigned short codetab[HSIZE];
100     code_int free_ent;
101     int clear_flg;
102     int offset;
103     long int in_count;
104     long int out_count;
105     int g_init_bits;
106     xgdIOCtx *g_outfile;
107     int ClearCode;
108     int EOFCode;
109     unsigned long cur_accum;
110     int cur_bits;
111     int a_count;
112     char accum[256];
113 } GifCtx;
114 
115 #define        MAXCOLORMAPSIZE         256
116 
117 #define        TRUE    1
118 #define        FALSE   0
119 
120 #define CM_RED         0
121 #define CM_GREEN       1
122 #define CM_BLUE                2
123 
124 #define        MAX_LWZ_BITS            12
125 
126 #define INTERLACE              0x40
127 #define LOCALCOLORMAP  0x80
128 
129 #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
130 #define        ReadOK(file,buffer,len) (xgdGetBuf(buffer, len, file) > 0)
131 #define LM_to_uint(a,b)                        (((b)<<8)|(a))
132 
133 #define STACK_SIZE ((1<<(MAX_LWZ_BITS))*2)
134 
135 typedef struct
136 {
137     unsigned char buf[280];
138     int curbit, lastbit, done, last_byte;
139 } CODE_STATIC_DATA;
140 
141 typedef struct
142 {
143     int fresh;
144     int code_size, set_code_size;
145     int max_code, max_code_size;
146     int firstcode, oldcode;
147     int clear_code, end_code;
148     int table[2][(1 << MAX_LWZ_BITS)];
149     int stack[STACK_SIZE], *sp;
150     CODE_STATIC_DATA scd;
151 } LZW_STATIC_DATA;
152 
153 static int
GetDataBlock_(xgdIOCtx * fd,unsigned char * buf,int * ZeroDataBlockP)154 GetDataBlock_ (xgdIOCtx * fd, unsigned char *buf, int *ZeroDataBlockP)
155 {
156     unsigned char count;
157     if (!ReadOK (fd, &count, 1))
158       {
159 	  return -1;
160       }
161     *ZeroDataBlockP = count == 0;
162     if ((count != 0) && (!ReadOK (fd, buf, count)))
163       {
164 	  return -1;
165       }
166     return count;
167 }
168 
169 static int
GetDataBlock(xgdIOCtx * fd,unsigned char * buf,int * ZeroDataBlockP)170 GetDataBlock (xgdIOCtx * fd, unsigned char *buf, int *ZeroDataBlockP)
171 {
172     int rv;
173     rv = GetDataBlock_ (fd, buf, ZeroDataBlockP);
174     return (rv);
175 }
176 
177 static int
ReadColorMap(xgdIOCtx * fd,int number,unsigned char (* buffer)[256])178 ReadColorMap (xgdIOCtx * fd, int number, unsigned char (*buffer)[256])
179 {
180     int i;
181     unsigned char rgb[3];
182     for (i = 0; i < number; ++i)
183       {
184 	  if (!ReadOK (fd, rgb, sizeof (rgb)))
185 	    {
186 		return TRUE;
187 	    }
188 	  buffer[CM_RED][i] = rgb[0];
189 	  buffer[CM_GREEN][i] = rgb[1];
190 	  buffer[CM_BLUE][i] = rgb[2];
191       }
192     return FALSE;
193 }
194 
195 static int
GetCode_(xgdIOCtx * fd,CODE_STATIC_DATA * scd,int code_size,int flag,int * ZeroDataBlockP)196 GetCode_ (xgdIOCtx * fd, CODE_STATIC_DATA * scd, int code_size, int flag,
197 	  int *ZeroDataBlockP)
198 {
199     int i, j, ret;
200     unsigned char count;
201     if (flag)
202       {
203 	  scd->curbit = 0;
204 	  scd->lastbit = 0;
205 	  scd->last_byte = 0;
206 	  scd->done = FALSE;
207 	  return 0;
208       }
209     if ((scd->curbit + code_size) >= scd->lastbit)
210       {
211 	  if (scd->done)
212 	    {
213 		if (scd->curbit >= scd->lastbit)
214 		  {
215 		      /* Oh well */
216 		  }
217 		return -1;
218 	    }
219 	  scd->buf[0] = scd->buf[scd->last_byte - 2];
220 	  scd->buf[1] = scd->buf[scd->last_byte - 1];
221 	  if ((count = GetDataBlock (fd, &scd->buf[2], ZeroDataBlockP)) <= 0)
222 	      scd->done = TRUE;
223 	  scd->last_byte = 2 + count;
224 	  scd->curbit = (scd->curbit - scd->lastbit) + 16;
225 	  scd->lastbit = (2 + count) * 8;
226       }
227     ret = 0;
228     for (i = scd->curbit, j = 0; j < code_size; ++i, ++j)
229 	ret |= ((scd->buf[i / 8] & (1 << (i % 8))) != 0) << j;
230     scd->curbit += code_size;
231     return ret;
232 }
233 
234 static int
GetCode(xgdIOCtx * fd,CODE_STATIC_DATA * scd,int code_size,int flag,int * ZeroDataBlockP)235 GetCode (xgdIOCtx * fd, CODE_STATIC_DATA * scd, int code_size, int flag,
236 	 int *ZeroDataBlockP)
237 {
238     int rv;
239     rv = GetCode_ (fd, scd, code_size, flag, ZeroDataBlockP);
240     return (rv);
241 }
242 
243 static int
LWZReadByte_(xgdIOCtx * fd,LZW_STATIC_DATA * sd,char flag,int input_code_size,int * ZeroDataBlockP)244 LWZReadByte_ (xgdIOCtx * fd, LZW_STATIC_DATA * sd, char flag,
245 	      int input_code_size, int *ZeroDataBlockP)
246 {
247     int code, incode, i;
248     if (flag)
249       {
250 	  sd->set_code_size = input_code_size;
251 	  sd->code_size = sd->set_code_size + 1;
252 	  sd->clear_code = 1 << sd->set_code_size;
253 	  sd->end_code = sd->clear_code + 1;
254 	  sd->max_code_size = 2 * sd->clear_code;
255 	  sd->max_code = sd->clear_code + 2;
256 	  GetCode (fd, &sd->scd, 0, TRUE, ZeroDataBlockP);
257 	  sd->fresh = TRUE;
258 	  for (i = 0; i < sd->clear_code; ++i)
259 	    {
260 		sd->table[0][i] = 0;
261 		sd->table[1][i] = i;
262 	    }
263 	  for (; i < (1 << MAX_LWZ_BITS); ++i)
264 	      sd->table[0][i] = sd->table[1][0] = 0;
265 	  sd->sp = sd->stack;
266 	  return 0;
267       }
268     else if (sd->fresh)
269       {
270 	  sd->fresh = FALSE;
271 	  do
272 	    {
273 		sd->firstcode = sd->oldcode =
274 		    GetCode (fd, &sd->scd, sd->code_size, FALSE,
275 			     ZeroDataBlockP);
276 	    }
277 	  while (sd->firstcode == sd->clear_code);
278 	  return sd->firstcode;
279       }
280     if (sd->sp > sd->stack)
281 	return *--sd->sp;
282     while ((code =
283 	    GetCode (fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP)) >= 0)
284       {
285 	  if (code == sd->clear_code)
286 	    {
287 		for (i = 0; i < sd->clear_code; ++i)
288 		  {
289 		      sd->table[0][i] = 0;
290 		      sd->table[1][i] = i;
291 		  }
292 		for (; i < (1 << MAX_LWZ_BITS); ++i)
293 		    sd->table[0][i] = sd->table[1][i] = 0;
294 		sd->code_size = sd->set_code_size + 1;
295 		sd->max_code_size = 2 * sd->clear_code;
296 		sd->max_code = sd->clear_code + 2;
297 		sd->sp = sd->stack;
298 		sd->firstcode = sd->oldcode =
299 		    GetCode (fd, &sd->scd, sd->code_size, FALSE,
300 			     ZeroDataBlockP);
301 		return sd->firstcode;
302 	    }
303 	  else if (code == sd->end_code)
304 	    {
305 		int count;
306 		unsigned char buf[260];
307 		if (*ZeroDataBlockP)
308 		    return -2;
309 		while ((count = GetDataBlock (fd, buf, ZeroDataBlockP)) > 0)
310 		    ;
311 		if (count != 0)
312 		    return -2;
313 	    }
314 	  incode = code;
315 	  if (sd->sp == (sd->stack + STACK_SIZE))
316 	    {
317 		return -1;
318 	    }
319 	  if (code >= sd->max_code)
320 	    {
321 		*sd->sp++ = sd->firstcode;
322 		code = sd->oldcode;
323 	    }
324 	  while (code >= sd->clear_code)
325 	    {
326 		if (sd->sp == (sd->stack + STACK_SIZE))
327 		  {
328 		      return -1;
329 		  }
330 		*sd->sp++ = sd->table[1][code];
331 		if (code == sd->table[0][code])
332 		  {
333 		      /* Oh well */
334 		  }
335 		code = sd->table[0][code];
336 	    }
337 	  *sd->sp++ = sd->firstcode = sd->table[1][code];
338 	  if ((code = sd->max_code) < (1 << MAX_LWZ_BITS))
339 	    {
340 		sd->table[0][code] = sd->oldcode;
341 		sd->table[1][code] = sd->firstcode;
342 		++sd->max_code;
343 		if ((sd->max_code >= sd->max_code_size) &&
344 		    (sd->max_code_size < (1 << MAX_LWZ_BITS)))
345 		  {
346 		      sd->max_code_size *= 2;
347 		      ++sd->code_size;
348 		  }
349 	    }
350 	  sd->oldcode = incode;
351 	  if (sd->sp > sd->stack)
352 	      return *--sd->sp;
353       }
354     return code;
355 }
356 
357 static int
LWZReadByte(xgdIOCtx * fd,LZW_STATIC_DATA * sd,char flag,int input_code_size,int * ZeroDataBlockP)358 LWZReadByte (xgdIOCtx * fd, LZW_STATIC_DATA * sd, char flag,
359 	     int input_code_size, int *ZeroDataBlockP)
360 {
361     int rv;
362     rv = LWZReadByte_ (fd, sd, flag, input_code_size, ZeroDataBlockP);
363     return (rv);
364 }
365 
366 static void
ReadImage(gGraphImagePtr img,xgdIOCtx * fd,unsigned char (* cmap)[256],int interlace,int * ZeroDataBlockP)367 ReadImage (gGraphImagePtr img, xgdIOCtx * fd,
368 	   unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP)
369 {
370     unsigned char c;
371     int v;
372     int xpos = 0, ypos = 0, pass = 0;
373     int i;
374     int red[256];
375     int green[256];
376     int blue[256];
377     unsigned char *p_out;
378     int len = img->width;
379     int height = img->height;
380     LZW_STATIC_DATA sd;
381     if (!ReadOK (fd, &c, 1))
382       {
383 	  return;
384       }
385     if (c > MAX_LWZ_BITS)
386       {
387 	  return;
388       }
389     for (i = 0; (i < 256); i++)
390       {
391 	  red[i] = cmap[CM_RED][i];
392 	  green[i] = cmap[CM_GREEN][i];
393 	  blue[i] = cmap[CM_BLUE][i];
394       }
395     if (LWZReadByte (fd, &sd, TRUE, c, ZeroDataBlockP) < 0)
396       {
397 	  return;
398       }
399     while ((v = LWZReadByte (fd, &sd, FALSE, c, ZeroDataBlockP)) >= 0)
400       {
401 	  if (v >= 256)
402 	    {
403 		v = 0;
404 	    }
405 	  p_out =
406 	      img->pixels + (ypos * img->scanline_width) +
407 	      (xpos * img->pixel_size);
408 	  if (img->pixel_format == GG_PIXEL_PALETTE)
409 	    {
410 		/* the output image is expected to be PALETTE-based */
411 		*p_out++ = v;
412 		if ((v + 1) > img->max_palette)
413 		    img->max_palette = v + 1;
414 		img->palette_red[v] = red[v];
415 		img->palette_green[v] = green[v];
416 		img->palette_blue[v] = blue[v];
417 	    }
418 	  ++xpos;
419 	  if (xpos == len)
420 	    {
421 		xpos = 0;
422 		if (interlace)
423 		  {
424 		      switch (pass)
425 			{
426 			case 0:
427 			case 1:
428 			    ypos += 8;
429 			    break;
430 			case 2:
431 			    ypos += 4;
432 			    break;
433 			case 3:
434 			    ypos += 2;
435 			    break;
436 			}
437 		      if (ypos >= height)
438 			{
439 			    ++pass;
440 			    switch (pass)
441 			      {
442 			      case 1:
443 				  ypos = 4;
444 				  break;
445 			      case 2:
446 				  ypos = 2;
447 				  break;
448 			      case 3:
449 				  ypos = 1;
450 				  break;
451 			      default:
452 				  goto fini;
453 			      }
454 			}
455 		  }
456 		else
457 		  {
458 		      ++ypos;
459 		  }
460 	    }
461 	  if (ypos >= height)
462 	      break;
463       }
464   fini:
465     if (LWZReadByte (fd, &sd, FALSE, c, ZeroDataBlockP) >= 0)
466       {
467 	  /* Ignore extra */
468       }
469 }
470 
471 static int
DoExtension(xgdIOCtx * fd,int label,int * Transparent,int * ZeroDataBlockP)472 DoExtension (xgdIOCtx * fd, int label, int *Transparent, int *ZeroDataBlockP)
473 {
474     unsigned char buf[256];
475     switch (label)
476       {
477       case 0xf9:
478 	  memset (buf, 0, 4);
479 	  (void) GetDataBlock (fd, (unsigned char *) buf, ZeroDataBlockP);
480 	  if ((buf[0] & 0x1) != 0)
481 	      *Transparent = buf[3];
482 	  while (GetDataBlock (fd, (unsigned char *) buf, ZeroDataBlockP) > 0);
483 	  return FALSE;
484       default:
485 	  break;
486       }
487     while (GetDataBlock (fd, (unsigned char *) buf, ZeroDataBlockP) > 0)
488 	;
489     return FALSE;
490 }
491 
492 static void
BumpPixel(GifCtx * ctx)493 BumpPixel (GifCtx * ctx)
494 {
495     ++(ctx->curx);
496     if (ctx->curx == ctx->Width)
497       {
498 	  ctx->curx = 0;
499 	  if (!ctx->Interlace)
500 	      ++(ctx->cury);
501 	  else
502 	    {
503 		switch (ctx->Pass)
504 		  {
505 		  case 0:
506 		      ctx->cury += 8;
507 		      if (ctx->cury >= ctx->Height)
508 			{
509 			    ++(ctx->Pass);
510 			    ctx->cury = 4;
511 			}
512 		      break;
513 		  case 1:
514 		      ctx->cury += 8;
515 		      if (ctx->cury >= ctx->Height)
516 			{
517 			    ++(ctx->Pass);
518 			    ctx->cury = 2;
519 			}
520 		      break;
521 		  case 2:
522 		      ctx->cury += 4;
523 		      if (ctx->cury >= ctx->Height)
524 			{
525 			    ++(ctx->Pass);
526 			    ctx->cury = 1;
527 			}
528 		      break;
529 
530 		  case 3:
531 		      ctx->cury += 2;
532 		      break;
533 		  }
534 	    }
535       }
536 }
537 
538 static int
GIFNextPixel(gGraphImagePtr img,GifCtx * ctx)539 GIFNextPixel (gGraphImagePtr img, GifCtx * ctx)
540 {
541     int pixel = 0;
542     unsigned char *p_in;
543     if (ctx->CountDown == 0)
544 	return EOF;
545     --(ctx->CountDown);
546 
547     p_in =
548 	img->pixels + (ctx->cury * img->scanline_width) +
549 	(ctx->curx * img->pixel_size);
550     if (img->pixel_format == GG_PIXEL_GRAYSCALE
551 	|| img->pixel_format == GG_PIXEL_PALETTE)
552       {
553 	  /* the input image is expected to be GRAYSCALE or PALETTE anyway */
554 	  pixel = *p_in;
555       }
556     BumpPixel (ctx);
557     return pixel;
558 }
559 
560 static void
xgdPutC(const unsigned char c,xgdIOCtx * ctx)561 xgdPutC (const unsigned char c, xgdIOCtx * ctx)
562 {
563     (ctx->putC) (ctx, c);
564 }
565 
566 static void
char_init(GifCtx * ctx)567 char_init (GifCtx * ctx)
568 {
569     ctx->a_count = 0;
570 }
571 
572 static void
cl_hash(register count_int chsize,GifCtx * ctx)573 cl_hash (register count_int chsize, GifCtx * ctx)
574 {
575     register count_int *htab_p = ctx->htab + chsize;
576     register long i;
577     register long m1 = -1;
578     i = chsize - 16;
579     do
580       {
581 	  *(htab_p - 16) = m1;
582 	  *(htab_p - 15) = m1;
583 	  *(htab_p - 14) = m1;
584 	  *(htab_p - 13) = m1;
585 	  *(htab_p - 12) = m1;
586 	  *(htab_p - 11) = m1;
587 	  *(htab_p - 10) = m1;
588 	  *(htab_p - 9) = m1;
589 	  *(htab_p - 8) = m1;
590 	  *(htab_p - 7) = m1;
591 	  *(htab_p - 6) = m1;
592 	  *(htab_p - 5) = m1;
593 	  *(htab_p - 4) = m1;
594 	  *(htab_p - 3) = m1;
595 	  *(htab_p - 2) = m1;
596 	  *(htab_p - 1) = m1;
597 	  htab_p -= 16;
598       }
599     while ((i -= 16) >= 0);
600     for (i += 16; i > 0; --i)
601 	*--htab_p = m1;
602 }
603 
604 static void
flush_char(GifCtx * ctx)605 flush_char (GifCtx * ctx)
606 {
607     if (ctx->a_count > 0)
608       {
609 	  xgdPutC (ctx->a_count, ctx->g_outfile);
610 	  xgdPutBuf (ctx->accum, ctx->a_count, ctx->g_outfile);
611 	  ctx->a_count = 0;
612       }
613 }
614 
615 static void
char_out(int c,GifCtx * ctx)616 char_out (int c, GifCtx * ctx)
617 {
618     ctx->accum[ctx->a_count++] = c;
619     if (ctx->a_count >= 254)
620 	flush_char (ctx);
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 
629 static void
output(code_int code,GifCtx * ctx)630 output (code_int code, GifCtx * ctx)
631 {
632     ctx->cur_accum &= masks[ctx->cur_bits];
633     if (ctx->cur_bits > 0)
634 	ctx->cur_accum |= ((long) code << ctx->cur_bits);
635     else
636 	ctx->cur_accum = code;
637     ctx->cur_bits += ctx->n_bits;
638     while (ctx->cur_bits >= 8)
639       {
640 	  char_out ((unsigned int) (ctx->cur_accum & 0xff), ctx);
641 	  ctx->cur_accum >>= 8;
642 	  ctx->cur_bits -= 8;
643       }
644     if (ctx->free_ent > ctx->maxcode || ctx->clear_flg)
645       {
646 
647 	  if (ctx->clear_flg)
648 	    {
649 
650 		ctx->maxcode = MAXCODE (ctx->n_bits = ctx->g_init_bits);
651 		ctx->clear_flg = 0;
652 
653 	    }
654 	  else
655 	    {
656 
657 		++(ctx->n_bits);
658 		if (ctx->n_bits == maxbits)
659 		    ctx->maxcode = maxmaxcode;
660 		else
661 		    ctx->maxcode = MAXCODE (ctx->n_bits);
662 	    }
663       }
664     if (code == ctx->EOFCode)
665       {
666 	  while (ctx->cur_bits > 0)
667 	    {
668 		char_out ((unsigned int) (ctx->cur_accum & 0xff), ctx);
669 		ctx->cur_accum >>= 8;
670 		ctx->cur_bits -= 8;
671 	    }
672 	  flush_char (ctx);
673       }
674 }
675 
676 static void
cl_block(GifCtx * ctx)677 cl_block (GifCtx * ctx)
678 {
679     cl_hash ((count_int) hsize, ctx);
680     ctx->free_ent = ctx->ClearCode + 2;
681     ctx->clear_flg = 1;
682     output ((code_int) ctx->ClearCode, ctx);
683 }
684 
685 static int
gifPutWord(int w,xgdIOCtx * out)686 gifPutWord (int w, xgdIOCtx * out)
687 {
688     xgdPutC (w & 0xFF, out);
689     xgdPutC ((w >> 8) & 0xFF, out);
690     return 0;
691 }
692 
693 static void
GIFcompress(int init_bits,xgdIOCtxPtr outfile,gGraphImagePtr img,GifCtx * ctx)694 GIFcompress (int init_bits, xgdIOCtxPtr outfile, gGraphImagePtr img,
695 	     GifCtx * ctx)
696 {
697 /*
698  * compress stdin to stdout
699  *
700  * Algorithm:  use open addressing double hashing (no chaining) on the
701  * prefix code / next character combination.  We do a variant of Knuth's
702  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
703  * secondary probe.  Here, the modular division first probe is gives way
704  * to a faster exclusive-or manipulation.  Also do block compression with
705  * an adaptive reset, whereby the code table is cleared when the compression
706  * ratio decreases, but after the table fills.  The variable-length output
707  * codes are re-sized at this point, and a special CLEAR code is generated
708  * for the decompressor.  Late addition:  construct the table according to
709  * file size for noticeable speed improvement on small files.  Please direct
710  * questions about this implementation to ames!jaw.
711  */
712     register long fcode;
713     register code_int i /* = 0 */ ;
714     register int c;
715     register code_int ent;
716     register code_int disp;
717     register code_int hsize_reg;
718     register int hshift;
719     ctx->g_init_bits = init_bits;
720     ctx->g_outfile = outfile;
721     ctx->offset = 0;
722     ctx->out_count = 0;
723     ctx->clear_flg = 0;
724     ctx->in_count = 1;
725     ctx->maxcode = MAXCODE (ctx->n_bits = ctx->g_init_bits);
726     ctx->ClearCode = (1 << (init_bits - 1));
727     ctx->EOFCode = ctx->ClearCode + 1;
728     ctx->free_ent = ctx->ClearCode + 2;
729     char_init (ctx);
730     ent = GIFNextPixel (img, ctx);
731     hshift = 0;
732     for (fcode = (long) hsize; fcode < 65536L; fcode *= 2L)
733 	++hshift;
734     hshift = 8 - hshift;
735     hsize_reg = hsize;
736     cl_hash ((count_int) hsize_reg, ctx);
737     output ((code_int) ctx->ClearCode, ctx);
738 #ifdef SIGNED_COMPARE_SLOW
739     while ((c = GIFNextPixel (img)) != (unsigned) EOF)
740       {
741 #else /*SIGNED_COMPARE_SLOW */
742     while ((c = GIFNextPixel (img, ctx)) != EOF)
743       {				/* } */
744 #endif /*SIGNED_COMPARE_SLOW */
745 	  ++(ctx->in_count);
746 	  fcode = (long) (((long) c << maxbits) + ent);
747 	  i = (((code_int) c << hshift) ^ ent);
748 	  if (HashTabOf (i) == fcode)
749 	    {
750 		ent = CodeTabOf (i);
751 		continue;
752 	    }
753 	  else if ((long) HashTabOf (i) < 0)
754 	      goto nomatch;
755 	  disp = hsize_reg - i;
756 	  if (i == 0)
757 	      disp = 1;
758 	probe:
759 	  if ((i -= disp) < 0)
760 	      i += hsize_reg;
761 	  if (HashTabOf (i) == fcode)
762 	    {
763 		ent = CodeTabOf (i);
764 		continue;
765 	    }
766 	  if ((long) HashTabOf (i) > 0)
767 	      goto probe;
768 	nomatch:
769 	  output ((code_int) ent, ctx);
770 	  ++(ctx->out_count);
771 	  ent = c;
772 #ifdef SIGNED_COMPARE_SLOW
773 	  if ((unsigned) ctx->free_ent < (unsigned) maxmaxcode)
774 	    {
775 #else /*SIGNED_COMPARE_SLOW */
776 	  if (ctx->free_ent < maxmaxcode)
777 	    {
778 #endif /*SIGNED_COMPARE_SLOW */
779 		CodeTabOf (i) = ctx->free_ent++;
780 		HashTabOf (i) = fcode;
781 	    }
782 	  else
783 	      cl_block (ctx);
784       }
785     output ((code_int) ent, ctx);
786     ++(ctx->out_count);
787     output ((code_int) ctx->EOFCode, ctx);
788 }
789 
790 static int
791 GIFEncode (xgdIOCtxPtr fp, int GInterlace,
792 	   int Background, int Transparent, int BitsPerPixel, int *Red,
793 	   int *Green, int *Blue, gGraphImagePtr img)
794 {
795     int B;
796     int RWidth, RHeight;
797     int LeftOfs, TopOfs;
798     int Resolution;
799     int ColorMapSize;
800     int InitCodeSize;
801     int i;
802     int GWidth = img->width;
803     int GHeight = img->height;
804     GifCtx ctx;
805     ctx.Interlace = GInterlace;
806     ctx.in_count = 1;
807     memset (&ctx, 0, sizeof (ctx));
808     ColorMapSize = 1 << BitsPerPixel;
809     RWidth = ctx.Width = GWidth;
810     RHeight = ctx.Height = GHeight;
811     LeftOfs = TopOfs = 0;
812     Resolution = BitsPerPixel;
813     ctx.CountDown = (long) ctx.Width * (long) ctx.Height;
814     ctx.Pass = 0;
815     if (BitsPerPixel <= 1)
816 	InitCodeSize = 2;
817     else
818 	InitCodeSize = BitsPerPixel;
819     ctx.curx = ctx.cury = 0;
820     xgdPutBuf (Transparent < 0 ? "GIF87a" : "GIF89a", 6, fp);
821     gifPutWord (RWidth, fp);
822     gifPutWord (RHeight, fp);
823     B = 0x80;
824     B |= (Resolution - 1) << 5;
825     B |= (BitsPerPixel - 1);
826     xgdPutC (B, fp);
827     xgdPutC (Background, fp);
828     xgdPutC (0, fp);
829     for (i = 0; i < ColorMapSize; ++i)
830       {
831 	  xgdPutC (Red[i], fp);
832 	  xgdPutC (Green[i], fp);
833 	  xgdPutC (Blue[i], fp);
834       }
835     if (Transparent >= 0)
836       {
837 	  xgdPutC ('!', fp);
838 	  xgdPutC (0xf9, fp);
839 	  xgdPutC (4, fp);
840 	  xgdPutC (1, fp);
841 	  xgdPutC (0, fp);
842 	  xgdPutC (0, fp);
843 	  xgdPutC ((unsigned char) Transparent, fp);
844 	  xgdPutC (0, fp);
845       }
846     xgdPutC (',', fp);
847     gifPutWord (LeftOfs, fp);
848     gifPutWord (TopOfs, fp);
849     gifPutWord (ctx.Width, fp);
850     gifPutWord (ctx.Height, fp);
851     if (ctx.Interlace)
852 	xgdPutC (0x40, fp);
853     else
854 	xgdPutC (0x00, fp);
855     xgdPutC (InitCodeSize, fp);
856     GIFcompress (InitCodeSize + 1, fp, img, &ctx);
857     xgdPutC (0, fp);
858     xgdPutC (';', fp);
859     return GGRAPH_OK;
860 }
861 
862 static int
863 colorstobpp (int colors)
864 {
865     int bpp = 0;
866 
867     if (colors <= 2)
868 	bpp = 1;
869     else if (colors <= 4)
870 	bpp = 2;
871     else if (colors <= 8)
872 	bpp = 3;
873     else if (colors <= 16)
874 	bpp = 4;
875     else if (colors <= 32)
876 	bpp = 5;
877     else if (colors <= 64)
878 	bpp = 6;
879     else if (colors <= 128)
880 	bpp = 7;
881     else if (colors <= 256)
882 	bpp = 8;
883     return bpp;
884 }
885 
886 static gGraphImageInfosPtr
887 xgdImageInfosFromGifCtx (xgdIOCtxPtr fd, int *errcode)
888 {
889     int BitPixel;
890     unsigned char buf[16];
891     int imw, imh, screen_width, screen_height;
892     int bitPixel;
893     gGraphImageInfosPtr infos = NULL;
894     if (!ReadOK (fd, buf, 6))
895       {
896 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
897 	  return NULL;
898       }
899     if (strncmp ((char *) buf, "GIF", 3) != 0)
900       {
901 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
902 	  return NULL;
903       }
904     if (memcmp ((char *) buf + 3, "87a", 3) == 0
905 	|| memcmp ((char *) buf + 3, "89a", 3) == 0)
906 	;
907     else
908       {
909 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
910 	  return NULL;
911       }
912     if (!ReadOK (fd, buf, 7))
913       {
914 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
915 	  return NULL;
916       }
917     BitPixel = 2 << (buf[4] & 0x07);
918     screen_width = imw = LM_to_uint (buf[0], buf[1]);
919     screen_height = imh = LM_to_uint (buf[2], buf[3]);
920     bitPixel = colorstobpp (BitPixel);
921     if (!
922 	(infos =
923 	 gg_image_infos_create (GG_PIXEL_PALETTE, screen_width, screen_height,
924 				bitPixel, 1, GGRAPH_SAMPLE_UINT, NULL, NULL)))
925       {
926 	  *errcode = GGRAPH_INSUFFICIENT_MEMORY;
927 	  return NULL;
928       }
929     infos->compression = GGRAPH_TIFF_COMPRESSION_LZW;
930     if (!infos)
931       {
932 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
933 	  return NULL;
934       }
935     return infos;
936 }
937 
938 static gGraphImagePtr
939 xgdImageCreateFromGifCtx (xgdIOCtxPtr fd, int *errcode)
940 {
941     int BitPixel;
942     int Transparent = (-1);
943     unsigned char buf[16];
944     unsigned char c;
945     unsigned char ColorMap[3][MAXCOLORMAPSIZE];
946     unsigned char localColorMap[3][MAXCOLORMAPSIZE];
947     int imw, imh, screen_width, screen_height;
948     int useGlobalColormap;
949     int bitPixel;
950     int ZeroDataBlock = FALSE;
951     int haveGlobalColormap;
952     gGraphImagePtr img = NULL;
953     if (!ReadOK (fd, buf, 6))
954       {
955 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
956 	  return NULL;
957       }
958     if (strncmp ((char *) buf, "GIF", 3) != 0)
959       {
960 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
961 	  return NULL;
962       }
963     if (memcmp ((char *) buf + 3, "87a", 3) == 0
964 	|| memcmp ((char *) buf + 3, "89a", 3) == 0)
965 	;
966     else
967       {
968 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
969 	  return NULL;
970       }
971     if (!ReadOK (fd, buf, 7))
972       {
973 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
974 	  return NULL;
975       }
976     BitPixel = 2 << (buf[4] & 0x07);
977     screen_width = imw = LM_to_uint (buf[0], buf[1]);
978     screen_height = imh = LM_to_uint (buf[2], buf[3]);
979     haveGlobalColormap = BitSet (buf[4], LOCALCOLORMAP);	/* Global Colormap */
980     if (haveGlobalColormap)
981       {
982 	  if (ReadColorMap (fd, BitPixel, ColorMap))
983 	    {
984 		*errcode = GGRAPH_GIF_CODEC_ERROR;
985 		return NULL;
986 	    }
987       }
988     for (;;)
989       {
990 	  int top, left;
991 	  int width, height;
992 	  if (!ReadOK (fd, &c, 1))
993 	    {
994 		*errcode = GGRAPH_GIF_CODEC_ERROR;
995 		return NULL;
996 	    }
997 	  if (c == ';')
998 	    {
999 		goto terminated;
1000 	    }
1001 
1002 	  if (c == '!')
1003 	    {
1004 		if (!ReadOK (fd, &c, 1))
1005 		  {
1006 		      *errcode = GGRAPH_GIF_CODEC_ERROR;
1007 		      return NULL;
1008 		  }
1009 		DoExtension (fd, c, &Transparent, &ZeroDataBlock);
1010 		continue;
1011 	    }
1012 
1013 	  if (c != ',')
1014 	    {
1015 		continue;
1016 	    }
1017 	  if (!ReadOK (fd, buf, 9))
1018 	    {
1019 		*errcode = GGRAPH_GIF_CODEC_ERROR;
1020 		return NULL;
1021 	    }
1022 	  useGlobalColormap = !BitSet (buf[8], LOCALCOLORMAP);
1023 	  bitPixel = 1 << ((buf[8] & 0x07) + 1);
1024 	  left = LM_to_uint (buf[0], buf[1]);
1025 	  top = LM_to_uint (buf[2], buf[3]);
1026 	  width = LM_to_uint (buf[4], buf[5]);
1027 	  height = LM_to_uint (buf[6], buf[7]);
1028 	  if (left + width > screen_width || top + height > screen_height)
1029 	    {
1030 		*errcode = GGRAPH_GIF_CODEC_ERROR;
1031 		return NULL;
1032 	    }
1033 	  if (!
1034 	      (img =
1035 	       gg_image_create (GG_PIXEL_PALETTE, width, height, bitPixel, 1,
1036 				GGRAPH_SAMPLE_UINT, NULL, NULL)))
1037 	    {
1038 		*errcode = GGRAPH_INSUFFICIENT_MEMORY;
1039 		return NULL;
1040 	    }
1041 	  if (!useGlobalColormap)
1042 	    {
1043 		if (ReadColorMap (fd, bitPixel, localColorMap))
1044 		  {
1045 		      gg_image_destroy (img);
1046 		      *errcode = GGRAPH_GIF_CODEC_ERROR;
1047 		      return NULL;
1048 		  }
1049 		ReadImage (img, fd, localColorMap,
1050 			   BitSet (buf[8], INTERLACE), &ZeroDataBlock);
1051 	    }
1052 	  else
1053 	    {
1054 		if (!haveGlobalColormap)
1055 		  {
1056 		      gg_image_destroy (img);
1057 		      *errcode = GGRAPH_GIF_CODEC_ERROR;
1058 		      return NULL;
1059 		  }
1060 		ReadImage (img, fd,
1061 			   ColorMap,
1062 			   BitSet (buf[8], INTERLACE), &ZeroDataBlock);
1063 	    }
1064       }
1065   terminated:
1066     if (!img)
1067       {
1068 	  *errcode = GGRAPH_GIF_CODEC_ERROR;
1069 	  return NULL;
1070       }
1071     return img;
1072 }
1073 
1074 static int
1075 xgdImageGifCtx (gGraphImagePtr img, xgdIOCtxPtr out, int is_transparent)
1076 {
1077     int BitsPerPixel;
1078     int Red[256];
1079     int Green[256];
1080     int Blue[256];
1081     int i, colors;
1082     int transparent_idx = -1;
1083     if (img->pixel_format == GG_PIXEL_GRAYSCALE)
1084       {
1085 	  /* generating a GRAYSCALE palette */
1086 	  colors = 256;
1087 	  for (i = 0; i < 256; i++)
1088 	    {
1089 		Red[i] = i;
1090 		Green[i] = i;
1091 		Blue[i] = i;
1092 	    }
1093       }
1094     else
1095       {
1096 	  /* copying the PALETTE from image */
1097 	  colors = 0;
1098 	  for (i = 0; i < img->max_palette; ++i)
1099 	    {
1100 		Red[i] = img->palette_red[i];
1101 		Green[i] = img->palette_green[i];
1102 		Blue[i] = img->palette_blue[i];
1103 		colors++;
1104 	    }
1105       }
1106     BitsPerPixel = colorstobpp (colors);
1107     if (is_transparent)
1108       {
1109 	  /* identifying the Transparent Color Index */
1110 	  for (i = 0; i < colors; ++i)
1111 	    {
1112 		if (Red[i] == img->transparent_red
1113 		    && Green[i] == img->transparent_green
1114 		    && Blue[i] == img->transparent_blue)
1115 		    transparent_idx = i;
1116 	    }
1117       }
1118     return GIFEncode (out, 0, 0, transparent_idx, BitsPerPixel, Red, Green,
1119 		      Blue, img);
1120 }
1121 
1122 GGRAPH_PRIVATE int
1123 gg_image_to_gif (const gGraphImagePtr img, void **mem_buf, int *mem_buf_size,
1124 		 FILE * file, int dest_type, int is_transparent)
1125 {
1126 /* compressing an image as GIF */
1127     int ret;
1128     void *rv;
1129     int size;
1130     xgdIOCtx *out;
1131 
1132 /* checkings args for validity */
1133     if (dest_type == GG_TARGET_IS_FILE)
1134       {
1135 	  if (!file)
1136 	      return GGRAPH_ERROR;
1137       }
1138     else
1139       {
1140 	  if (!mem_buf || !mem_buf_size)
1141 	      return GGRAPH_ERROR;
1142 	  *mem_buf = NULL;
1143 	  *mem_buf_size = 0;
1144       }
1145 
1146     if (dest_type == GG_TARGET_IS_FILE)
1147 	out = xgdNewDynamicCtx (0, file, dest_type);
1148     else
1149 	out = xgdNewDynamicCtx (2048, NULL, dest_type);
1150     ret = xgdImageGifCtx (img, out, is_transparent);
1151     if (dest_type == GG_TARGET_IS_FILE)
1152       {
1153 	  out->xgd_free (out);
1154 	  return ret;
1155       }
1156 
1157     if (ret == GGRAPH_OK)
1158 	rv = xgdDPExtractData (out, &size);
1159     out->xgd_free (out);
1160     *mem_buf = rv;
1161     *mem_buf_size = size;
1162     return ret;
1163 }
1164 
1165 GGRAPH_PRIVATE int
1166 gg_image_from_gif (int size, const void *data, int source_type,
1167 		   gGraphImagePtr * image_handle)
1168 {
1169 /* uncompressing a GIF */
1170     int errcode = GGRAPH_OK;
1171     gGraphImagePtr img;
1172     xgdIOCtx *in =
1173 	xgdNewDynamicCtxEx (size, data, XGD_CTX_DONT_FREE, source_type);
1174     img = xgdImageCreateFromGifCtx (in, &errcode);
1175     in->xgd_free (in);
1176     *image_handle = img;
1177     return errcode;
1178 }
1179 
1180 GGRAPH_PRIVATE int
1181 gg_image_infos_from_gif (int size, const void *data, int source_type,
1182 			 gGraphImageInfosPtr * infos_handle)
1183 {
1184 /* image infos from GIF */
1185     int errcode = GGRAPH_OK;
1186     gGraphImageInfosPtr infos;
1187     xgdIOCtx *in =
1188 	xgdNewDynamicCtxEx (size, data, XGD_CTX_DONT_FREE, source_type);
1189     infos = xgdImageInfosFromGifCtx (in, &errcode);
1190     in->xgd_free (in);
1191     *infos_handle = infos;
1192     return errcode;
1193 }
1194