1 /*
2  * "$Id: image-gif.c 7720 2008-07-11 22:46:21Z mike $"
3  *
4  *   GIF image routines for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 2007-2008 by Apple Inc.
7  *   Copyright 1993-2007 by Easy Software Products.
8  *
9  *   These coded instructions, statements, and computer programs are the
10  *   property of Apple Inc. and are protected by Federal copyright
11  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12  *   which should have been included with this file.  If this file is
13  *   file is missing or damaged, see the license at "http://www.cups.org/".
14  *
15  *   This file is subject to the Apple OS-Developed Software exception.
16  *
17  * Contents:
18  *
19  *   _cupsImageReadGIF() - Read a GIF image file.
20  *   gif_get_block()     - Read a GIF data block...
21  *   gif_get_code()      - Get a LZW code from the file...
22  *   gif_read_cmap()     - Read the colormap from a GIF file...
23  *   gif_read_image()    - Read a GIF image stream...
24  *   gif_read_lzw()      - Read a byte from the LZW stream...
25  */
26 
27 /*
28  * Include necessary headers...
29  */
30 
31 #include "image-private.h"
32 
33 
34 /*
35  * GIF definitions...
36  */
37 
38 #define GIF_INTERLACE	0x40
39 #define GIF_COLORMAP	0x80
40 #define GIF_MAX_BITS	12
41 
42 typedef cups_ib_t	gif_cmap_t[256][4];
43 typedef short		gif_table_t[4096];
44 
45 
46 /*
47  * Local globals...
48  */
49 
50 static int	gif_eof = 0;		/* Did we hit EOF? */
51 
52 
53 /*
54  * Local functions...
55  */
56 
57 static int	gif_get_block(FILE *fp, unsigned char *buffer);
58 static int	gif_get_code (FILE *fp, int code_size, int first_time);
59 static int	gif_read_cmap(FILE *fp, int ncolors, gif_cmap_t cmap,
60 		              int *gray);
61 static int	gif_read_image(FILE *fp, cups_image_t *img, gif_cmap_t cmap,
62 		               int interlace);
63 static int	gif_read_lzw(FILE *fp, int first_time, int input_code_size);
64 
65 
66 /*
67  * '_cupsImageReadGIF()' - Read a GIF image file.
68  */
69 
70 int					/* O - Read status */
_cupsImageReadGIF(cups_image_t * img,FILE * fp,cups_icspace_t primary,cups_icspace_t secondary,int saturation,int hue,const cups_ib_t * lut)71 _cupsImageReadGIF(
72     cups_image_t    *img,		/* IO - cupsImage */
73     FILE            *fp,		/* I - cupsImage file */
74     cups_icspace_t  primary,		/* I - Primary choice for colorspace */
75     cups_icspace_t  secondary,		/* I - Secondary choice for colorspace */
76     int             saturation,		/* I - Color saturation (%) */
77     int             hue,		/* I - Color hue (degrees) */
78     const cups_ib_t *lut)		/* I - Lookup table for gamma/brightness */
79 {
80   unsigned char	buf[1024];		/* Input buffer */
81   gif_cmap_t	cmap;			/* Colormap */
82   int		i,			/* Looping var */
83 		bpp,			/* Bytes per pixel */
84 		gray,			/* Grayscale image? */
85 		ncolors,		/* Bits per pixel */
86 		transparent;		/* Transparent color index */
87 
88 
89  /*
90   * GIF files are either grayscale or RGB - no CMYK...
91   */
92 
93   if (primary == CUPS_IMAGE_RGB_CMYK)
94     primary = CUPS_IMAGE_RGB;
95 
96  /*
97   * Read the header; we already know it is a GIF file...
98   */
99 
100   fread(buf, 13, 1, fp);
101 
102   img->xsize = (buf[7] << 8) | buf[6];
103   img->ysize = (buf[9] << 8) | buf[8];
104   ncolors    = 2 << (buf[10] & 0x07);
105   gray       = primary == CUPS_IMAGE_BLACK || primary == CUPS_IMAGE_WHITE;
106 
107   if (buf[10] & GIF_COLORMAP)
108     if (gif_read_cmap(fp, ncolors, cmap, &gray))
109     {
110       fclose(fp);
111       return (-1);
112     }
113 
114   transparent = -1;
115 
116   for (;;)
117   {
118     switch (getc(fp))
119     {
120       case ';' :	/* End of image */
121           fclose(fp);
122           return (-1);		/* Early end of file */
123 
124       case '!' :	/* Extension record */
125           buf[0] = getc(fp);
126           if (buf[0] == 0xf9)	/* Graphic Control Extension */
127           {
128             gif_get_block(fp, buf);
129             if (buf[0] & 1)	/* Get transparent color index */
130               transparent = buf[3];
131           }
132 
133           while (gif_get_block(fp, buf) != 0);
134           break;
135 
136       case ',' :	/* cupsImage data */
137           fread(buf, 9, 1, fp);
138 
139           if (buf[8] & GIF_COLORMAP)
140           {
141             ncolors = 2 << (buf[8] & 0x07);
142             gray = primary == CUPS_IMAGE_BLACK || primary == CUPS_IMAGE_WHITE;
143 
144 	    if (gif_read_cmap(fp, ncolors, cmap, &gray))
145 	    {
146               fclose(fp);
147 	      return (-1);
148 	    }
149 	  }
150 
151           if (transparent >= 0)
152           {
153            /*
154             * Make transparent color white...
155             */
156 
157             cmap[transparent][0] = 255;
158             cmap[transparent][1] = 255;
159             cmap[transparent][2] = 255;
160           }
161 
162 	  if (gray)
163 	  {
164 	    switch (secondary)
165 	    {
166               case CUPS_IMAGE_CMYK :
167         	  for (i = ncolors - 1; i >= 0; i --)
168         	    cupsImageWhiteToCMYK(cmap[i], cmap[i], 1);
169         	  break;
170               case CUPS_IMAGE_CMY :
171         	  for (i = ncolors - 1; i >= 0; i --)
172         	    cupsImageWhiteToCMY(cmap[i], cmap[i], 1);
173         	  break;
174               case CUPS_IMAGE_BLACK :
175         	  for (i = ncolors - 1; i >= 0; i --)
176         	    cupsImageWhiteToBlack(cmap[i], cmap[i], 1);
177         	  break;
178               case CUPS_IMAGE_WHITE :
179         	  break;
180               case CUPS_IMAGE_RGB :
181               case CUPS_IMAGE_RGB_CMYK :
182         	  for (i = ncolors - 1; i >= 0; i --)
183         	    cupsImageWhiteToRGB(cmap[i], cmap[i], 1);
184         	  break;
185 	    }
186 
187             img->colorspace = secondary;
188 	  }
189 	  else
190 	  {
191 	    if (hue != 0 || saturation != 100)
192               for (i = ncolors - 1; i >= 0; i --)
193         	cupsImageRGBAdjust(cmap[i], 1, saturation, hue);
194 
195 	    switch (primary)
196 	    {
197               case CUPS_IMAGE_CMYK :
198         	  for (i = ncolors - 1; i >= 0; i --)
199         	    cupsImageRGBToCMYK(cmap[i], cmap[i], 1);
200         	  break;
201               case CUPS_IMAGE_CMY :
202         	  for (i = ncolors - 1; i >= 0; i --)
203         	    cupsImageRGBToCMY(cmap[i], cmap[i], 1);
204         	  break;
205               case CUPS_IMAGE_BLACK :
206         	  for (i = ncolors - 1; i >= 0; i --)
207         	    cupsImageRGBToBlack(cmap[i], cmap[i], 1);
208         	  break;
209               case CUPS_IMAGE_WHITE :
210         	  for (i = ncolors - 1; i >= 0; i --)
211         	    cupsImageRGBToWhite(cmap[i], cmap[i], 1);
212         	  break;
213               case CUPS_IMAGE_RGB :
214               case CUPS_IMAGE_RGB_CMYK :
215         	  for (i = ncolors - 1; i >= 0; i --)
216         	    cupsImageRGBToRGB(cmap[i], cmap[i], 1);
217         	  break;
218 	    }
219 
220             img->colorspace = primary;
221 	  }
222 
223           if (lut)
224 	  {
225 	    bpp = cupsImageGetDepth(img);
226 
227             for (i = ncolors - 1; i >= 0; i --)
228               cupsImageLut(cmap[i], bpp, lut);
229 	  }
230 
231           img->xsize = (buf[5] << 8) | buf[4];
232           img->ysize = (buf[7] << 8) | buf[6];
233 
234          /*
235 	  * Check the dimensions of the image; since the dimensions are
236 	  * a 16-bit integer we just need to check for 0...
237 	  */
238 
239           if (img->xsize == 0 || img->ysize == 0)
240 	  {
241 	    fprintf(stderr, "DEBUG: Bad GIF image dimensions: %dx%d\n",
242 	            img->xsize, img->ysize);
243 	    fclose(fp);
244 	    return (1);
245 	  }
246 
247 	  i = gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE);
248           fclose(fp);
249           return (i);
250     }
251   }
252 }
253 
254 
255 /*
256  * 'gif_get_block()' - Read a GIF data block...
257  */
258 
259 static int				/* O - Number characters read */
gif_get_block(FILE * fp,unsigned char * buf)260 gif_get_block(FILE          *fp,	/* I - File to read from */
261 	      unsigned char *buf)	/* I - Input buffer */
262 {
263   int	count;				/* Number of character to read */
264 
265 
266  /*
267   * Read the count byte followed by the data from the file...
268   */
269 
270   if ((count = getc(fp)) == EOF)
271   {
272     gif_eof = 1;
273     return (-1);
274   }
275   else if (count == 0)
276     gif_eof = 1;
277   else if (fread(buf, 1, count, fp) < count)
278   {
279     gif_eof = 1;
280     return (-1);
281   }
282   else
283     gif_eof = 0;
284 
285   return (count);
286 }
287 
288 
289 /*
290  * 'gif_get_code()' - Get a LZW code from the file...
291  */
292 
293 static int				/* O - LZW code */
gif_get_code(FILE * fp,int code_size,int first_time)294 gif_get_code(FILE *fp,			/* I - File to read from */
295 	     int  code_size,		/* I - Size of code in bits */
296 	     int  first_time)		/* I - 1 = first time, 0 = not first time */
297 {
298   unsigned		i, j,		/* Looping vars */
299 			ret;		/* Return value */
300   int			count;		/* Number of bytes read */
301   static unsigned char	buf[280];	/* Input buffer */
302   static unsigned	curbit,		/* Current bit */
303 			lastbit,	/* Last bit in buffer */
304 			done,		/* Done with this buffer? */
305 			last_byte;	/* Last byte in buffer */
306   static const unsigned char bits[8] =	/* Bit masks for codes */
307 			{
308 			  0x01, 0x02, 0x04, 0x08,
309 			  0x10, 0x20, 0x40, 0x80
310 			};
311 
312 
313   if (first_time)
314   {
315    /*
316     * Just initialize the input buffer...
317     */
318 
319     curbit    = 0;
320     lastbit   = 0;
321     last_byte = 0;
322     done      = 0;
323 
324     return (0);
325   }
326 
327   if ((curbit + code_size) >= lastbit)
328   {
329    /*
330     * Don't have enough bits to hold the code...
331     */
332 
333     if (done)
334       return (-1);	/* Sorry, no more... */
335 
336    /*
337     * Move last two bytes to front of buffer...
338     */
339 
340     if (last_byte > 1)
341     {
342       buf[0]    = buf[last_byte - 2];
343       buf[1]    = buf[last_byte - 1];
344       last_byte = 2;
345     }
346     else if (last_byte == 1)
347     {
348       buf[0]    = buf[last_byte - 1];
349       last_byte = 1;
350     }
351 
352    /*
353     * Read in another buffer...
354     */
355 
356     if ((count = gif_get_block (fp, buf + last_byte)) <= 0)
357     {
358      /*
359       * Whoops, no more data!
360       */
361 
362       done = 1;
363       return (-1);
364     }
365 
366    /*
367     * Update buffer state...
368     */
369 
370     curbit    = (curbit - lastbit) + 8 * last_byte;
371     last_byte += count;
372     lastbit   = last_byte * 8;
373   }
374 
375   for (ret = 0, i = curbit + code_size - 1, j = code_size;
376        j > 0;
377        i --, j --)
378     ret = (ret << 1) | ((buf[i / 8] & bits[i & 7]) != 0);
379 
380   curbit += code_size;
381 
382   return ret;
383 }
384 
385 
386 /*
387  * 'gif_read_cmap()' - Read the colormap from a GIF file...
388  */
389 
390 static int				/* O - -1 on error, 0 on success */
gif_read_cmap(FILE * fp,int ncolors,gif_cmap_t cmap,int * gray)391 gif_read_cmap(FILE       *fp,		/* I - File to read from */
392   	      int        ncolors,	/* I - Number of colors in file */
393 	      gif_cmap_t cmap,		/* O - Colormap information */
394 	      int        *gray)		/* IO - Is the image grayscale? */
395 {
396   int	i;				/* Looping var */
397 
398 
399  /*
400   * Read the colormap...
401   */
402 
403   for (i = 0; i < ncolors; i ++)
404     if (fread(cmap[i], 3, 1, fp) < 1)
405       return (-1);
406 
407  /*
408   * Check to see if the colormap is a grayscale ramp...
409   */
410 
411   for (i = 0; i < ncolors; i ++)
412     if (cmap[i][0] != cmap[i][1] || cmap[i][1] != cmap[i][2])
413       break;
414 
415   if (i == ncolors)
416   {
417     *gray = 1;
418     return (0);
419   }
420 
421  /*
422   * If this needs to be a grayscale image, convert the RGB values to
423   * luminance values...
424   */
425 
426   if (*gray)
427     for (i = 0; i < ncolors; i ++)
428       cmap[i][0] = (cmap[i][0] * 31 + cmap[i][1] * 61 + cmap[i][2] * 8) / 100;
429 
430   return (0);
431 }
432 
433 
434 /*
435  * 'gif_read_image()' - Read a GIF image stream...
436  */
437 
438 static int				/* I - 0 = success, -1 = failure */
gif_read_image(FILE * fp,cups_image_t * img,gif_cmap_t cmap,int interlace)439 gif_read_image(FILE         *fp,	/* I - Input file */
440 	       cups_image_t *img,	/* I - cupsImage pointer */
441 	       gif_cmap_t   cmap,	/* I - Colormap */
442 	       int          interlace)	/* I - Non-zero = interlaced image */
443 {
444   unsigned char		code_size;	/* Code size */
445   cups_ib_t		*pixels,	/* Pixel buffer */
446 			*temp;		/* Current pixel */
447   int			xpos,		/* Current X position */
448 			ypos,		/* Current Y position */
449 			pass;		/* Current pass */
450   int			pixel;		/* Current pixel */
451   int			bpp;		/* Bytes per pixel */
452   static const int	xpasses[4] =	/* X interleaving */
453 			{ 8, 8, 4, 2 },
454 			ypasses[5] =	/* Y interleaving */
455 			{ 0, 4, 2, 1, 999999 };
456 
457 
458   bpp       = cupsImageGetDepth(img);
459   pixels    = calloc(bpp, img->xsize);
460   xpos      = 0;
461   ypos      = 0;
462   pass      = 0;
463   code_size = getc(fp);
464 
465   if (code_size > GIF_MAX_BITS || !pixels)
466     return (-1);
467 
468   if (gif_read_lzw(fp, 1, code_size) < 0)
469   {
470     free(pixels);
471     return (-1);
472   }
473 
474   temp = pixels;
475   while ((pixel = gif_read_lzw(fp, 0, code_size)) >= 0)
476   {
477     switch (bpp)
478     {
479       case 4 :
480           temp[3] = cmap[pixel][3];
481       case 3 :
482           temp[2] = cmap[pixel][2];
483       case 2 :
484           temp[1] = cmap[pixel][1];
485       default :
486           temp[0] = cmap[pixel][0];
487     }
488 
489     xpos ++;
490     temp += bpp;
491     if (xpos == img->xsize)
492     {
493       _cupsImagePutRow(img, 0, ypos, img->xsize, pixels);
494 
495       xpos = 0;
496       temp = pixels;
497 
498       if (interlace)
499       {
500         ypos += xpasses[pass];
501 
502         if (ypos >= img->ysize)
503 	{
504 	  pass ++;
505 
506           ypos = ypasses[pass];
507 	}
508       }
509       else
510 	ypos ++;
511     }
512 
513     if (ypos >= img->ysize)
514       break;
515   }
516 
517   free(pixels);
518 
519   return (0);
520 }
521 
522 
523 /*
524  * 'gif_read_lzw()' - Read a byte from the LZW stream...
525  */
526 
527 static int				/* I - Byte from stream */
gif_read_lzw(FILE * fp,int first_time,int input_code_size)528 gif_read_lzw(FILE *fp,			/* I - File to read from */
529 	     int  first_time,		/* I - 1 = first time, 0 = not first time */
530  	     int  input_code_size)	/* I - Code size in bits */
531 {
532   int			i,		/* Looping var */
533 			code,		/* Current code */
534 			incode;		/* Input code */
535   static short		fresh = 0,	/* 1 = empty buffers */
536 			code_size,	/* Current code size */
537 			set_code_size,	/* Initial code size set */
538 			max_code,	/* Maximum code used */
539 			max_code_size,	/* Maximum code size */
540 			firstcode,	/* First code read */
541 			oldcode,	/* Last code read */
542 			clear_code,	/* Clear code for LZW input */
543 			end_code,	/* End code for LZW input */
544 			*stack = NULL,	/* Output stack */
545 			*sp;		/* Current stack pointer */
546   static gif_table_t	*table = NULL;	/* String table */
547 
548 
549   if (first_time)
550   {
551    /*
552     * Setup LZW state...
553     */
554 
555     set_code_size = input_code_size;
556     code_size     = set_code_size + 1;
557     clear_code    = 1 << set_code_size;
558     end_code      = clear_code + 1;
559     max_code_size = 2 * clear_code;
560     max_code      = clear_code + 2;
561 
562    /*
563     * Allocate memory for buffers...
564     */
565 
566     if (table == NULL)
567       table = calloc(2, sizeof(gif_table_t));
568 
569     if (table == NULL)
570       return (-1);
571 
572     if (stack == NULL)
573       stack = calloc(8192, sizeof(short));
574 
575     if (stack == NULL)
576       return (-1);
577 
578    /*
579     * Initialize input buffers...
580     */
581 
582     gif_get_code(fp, 0, 1);
583 
584    /*
585     * Wipe the decompressor table...
586     */
587 
588     fresh = 1;
589 
590     for (i = 0; i < clear_code; i ++)
591     {
592       table[0][i] = 0;
593       table[1][i] = i;
594     }
595 
596     for (; i < 4096; i ++)
597       table[0][i] = table[1][0] = 0;
598 
599     sp = stack;
600 
601     return (0);
602   }
603   else if (fresh)
604   {
605     fresh = 0;
606 
607     do
608       firstcode = oldcode = gif_get_code(fp, code_size, 0);
609     while (firstcode == clear_code);
610 
611     return (firstcode);
612   }
613   else if (!table)
614     return (0);
615 
616   if (sp > stack)
617     return (*--sp);
618 
619   while ((code = gif_get_code (fp, code_size, 0)) >= 0)
620   {
621     if (code == clear_code)
622     {
623       for (i = 0; i < clear_code; i ++)
624       {
625 	table[0][i] = 0;
626 	table[1][i] = i;
627       }
628 
629       for (; i < 4096; i ++)
630 	table[0][i] = table[1][i] = 0;
631 
632       code_size     = set_code_size + 1;
633       max_code_size = 2 * clear_code;
634       max_code      = clear_code + 2;
635 
636       sp = stack;
637 
638       firstcode = oldcode = gif_get_code(fp, code_size, 0);
639 
640       return (firstcode);
641     }
642     else if (code == end_code)
643     {
644       unsigned char	buf[260];
645 
646 
647       if (!gif_eof)
648         while (gif_get_block(fp, buf) > 0);
649 
650       return (-2);
651     }
652 
653     incode = code;
654 
655     if (code >= max_code)
656     {
657       *sp++ = firstcode;
658       code  = oldcode;
659     }
660 
661     while (code >= clear_code)
662     {
663       *sp++ = table[1][code];
664       if (code == table[0][code])
665 	return (255);
666 
667       code = table[0][code];
668     }
669 
670     *sp++ = firstcode = table[1][code];
671     code  = max_code;
672 
673     if (code < 4096)
674     {
675       table[0][code] = oldcode;
676       table[1][code] = firstcode;
677       max_code ++;
678 
679       if (max_code >= max_code_size && max_code_size < 4096)
680       {
681 	max_code_size *= 2;
682 	code_size ++;
683       }
684     }
685 
686     oldcode = incode;
687 
688     if (sp > stack)
689       return (*--sp);
690   }
691 
692   return (code);
693 }
694 
695 
696 /*
697  * End of "$Id: image-gif.c 7720 2008-07-11 22:46:21Z mike $".
698  */
699