]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/image-gif.c
Import CUPS 1.4svn-r7226.
[thirdparty/cups.git] / filter / image-gif.c
1 /*
2 * "$Id: image-gif.c 6649 2007-07-11 21:46:42Z 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
41 typedef cups_ib_t gif_cmap_t[256][4];
42 typedef short gif_table_t[4096];
43
44
45 /*
46 * Local globals...
47 */
48
49 static int gif_eof = 0; /* Did we hit EOF? */
50
51
52 /*
53 * Local functions...
54 */
55
56 static int gif_get_block(FILE *fp, unsigned char *buffer);
57 static int gif_get_code (FILE *fp, int code_size, int first_time);
58 static int gif_read_cmap(FILE *fp, int ncolors, gif_cmap_t cmap,
59 int *gray);
60 static int gif_read_image(FILE *fp, cups_image_t *img, gif_cmap_t cmap,
61 int interlace);
62 static int gif_read_lzw(FILE *fp, int first_time, int input_code_size);
63
64
65 /*
66 * '_cupsImageReadGIF()' - Read a GIF image file.
67 */
68
69 int /* O - Read status */
70 _cupsImageReadGIF(
71 cups_image_t *img, /* IO - cupsImage */
72 FILE *fp, /* I - cupsImage file */
73 cups_icspace_t primary, /* I - Primary choice for colorspace */
74 cups_icspace_t secondary, /* I - Secondary choice for colorspace */
75 int saturation, /* I - Color saturation (%) */
76 int hue, /* I - Color hue (degrees) */
77 const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
78 {
79 unsigned char buf[1024]; /* Input buffer */
80 gif_cmap_t cmap; /* Colormap */
81 int i, /* Looping var */
82 bpp, /* Bytes per pixel */
83 gray, /* Grayscale image? */
84 ncolors, /* Bits per pixel */
85 transparent; /* Transparent color index */
86
87
88 /*
89 * GIF files are either grayscale or RGB - no CMYK...
90 */
91
92 if (primary == CUPS_IMAGE_RGB_CMYK)
93 primary = CUPS_IMAGE_RGB;
94
95 /*
96 * Read the header; we already know it is a GIF file...
97 */
98
99 fread(buf, 13, 1, fp);
100
101 img->xsize = (buf[7] << 8) | buf[6];
102 img->ysize = (buf[9] << 8) | buf[8];
103 ncolors = 2 << (buf[10] & 0x07);
104 gray = primary == CUPS_IMAGE_BLACK || primary == CUPS_IMAGE_WHITE;
105
106 if (buf[10] & GIF_COLORMAP)
107 if (gif_read_cmap(fp, ncolors, cmap, &gray))
108 {
109 fclose(fp);
110 return (-1);
111 }
112
113 transparent = -1;
114
115 for (;;)
116 {
117 switch (getc(fp))
118 {
119 case ';' : /* End of image */
120 fclose(fp);
121 return (-1); /* Early end of file */
122
123 case '!' : /* Extension record */
124 buf[0] = getc(fp);
125 if (buf[0] == 0xf9) /* Graphic Control Extension */
126 {
127 gif_get_block(fp, buf);
128 if (buf[0] & 1) /* Get transparent color index */
129 transparent = buf[3];
130 }
131
132 while (gif_get_block(fp, buf) != 0);
133 break;
134
135 case ',' : /* cupsImage data */
136 fread(buf, 9, 1, fp);
137
138 if (buf[8] & GIF_COLORMAP)
139 {
140 ncolors = 2 << (buf[8] & 0x07);
141 gray = primary == CUPS_IMAGE_BLACK || primary == CUPS_IMAGE_WHITE;
142
143 if (gif_read_cmap(fp, ncolors, cmap, &gray))
144 {
145 fclose(fp);
146 return (-1);
147 }
148 }
149
150 if (transparent >= 0)
151 {
152 /*
153 * Make transparent color white...
154 */
155
156 cmap[transparent][0] = 255;
157 cmap[transparent][1] = 255;
158 cmap[transparent][2] = 255;
159 }
160
161 if (gray)
162 {
163 switch (secondary)
164 {
165 case CUPS_IMAGE_CMYK :
166 for (i = ncolors - 1; i >= 0; i --)
167 cupsImageWhiteToCMYK(cmap[i], cmap[i], 1);
168 break;
169 case CUPS_IMAGE_CMY :
170 for (i = ncolors - 1; i >= 0; i --)
171 cupsImageWhiteToCMY(cmap[i], cmap[i], 1);
172 break;
173 case CUPS_IMAGE_BLACK :
174 for (i = ncolors - 1; i >= 0; i --)
175 cupsImageWhiteToBlack(cmap[i], cmap[i], 1);
176 break;
177 case CUPS_IMAGE_WHITE :
178 break;
179 case CUPS_IMAGE_RGB :
180 case CUPS_IMAGE_RGB_CMYK :
181 for (i = ncolors - 1; i >= 0; i --)
182 cupsImageWhiteToRGB(cmap[i], cmap[i], 1);
183 break;
184 }
185
186 img->colorspace = secondary;
187 }
188 else
189 {
190 if (hue != 0 || saturation != 100)
191 for (i = ncolors - 1; i >= 0; i --)
192 cupsImageRGBAdjust(cmap[i], 1, saturation, hue);
193
194 switch (primary)
195 {
196 case CUPS_IMAGE_CMYK :
197 for (i = ncolors - 1; i >= 0; i --)
198 cupsImageRGBToCMYK(cmap[i], cmap[i], 1);
199 break;
200 case CUPS_IMAGE_CMY :
201 for (i = ncolors - 1; i >= 0; i --)
202 cupsImageRGBToCMY(cmap[i], cmap[i], 1);
203 break;
204 case CUPS_IMAGE_BLACK :
205 for (i = ncolors - 1; i >= 0; i --)
206 cupsImageRGBToBlack(cmap[i], cmap[i], 1);
207 break;
208 case CUPS_IMAGE_WHITE :
209 for (i = ncolors - 1; i >= 0; i --)
210 cupsImageRGBToWhite(cmap[i], cmap[i], 1);
211 break;
212 case CUPS_IMAGE_RGB :
213 case CUPS_IMAGE_RGB_CMYK :
214 for (i = ncolors - 1; i >= 0; i --)
215 cupsImageRGBToRGB(cmap[i], cmap[i], 1);
216 break;
217 }
218
219 img->colorspace = primary;
220 }
221
222 if (lut)
223 {
224 bpp = cupsImageGetDepth(img);
225
226 for (i = ncolors - 1; i >= 0; i --)
227 cupsImageLut(cmap[i], bpp, lut);
228 }
229
230 img->xsize = (buf[5] << 8) | buf[4];
231 img->ysize = (buf[7] << 8) | buf[6];
232
233 /*
234 * Check the dimensions of the image; since the dimensions are
235 * a 16-bit integer we just need to check for 0...
236 */
237
238 if (img->xsize == 0 || img->ysize == 0)
239 {
240 fprintf(stderr, "DEBUG: Bad GIF image dimensions: %dx%d\n",
241 img->xsize, img->ysize);
242 fclose(fp);
243 return (1);
244 }
245
246 i = gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE);
247 fclose(fp);
248 return (i);
249 }
250 }
251 }
252
253
254 /*
255 * 'gif_get_block()' - Read a GIF data block...
256 */
257
258 static int /* O - Number characters read */
259 gif_get_block(FILE *fp, /* I - File to read from */
260 unsigned char *buf) /* I - Input buffer */
261 {
262 int count; /* Number of character to read */
263
264
265 /*
266 * Read the count byte followed by the data from the file...
267 */
268
269 if ((count = getc(fp)) == EOF)
270 {
271 gif_eof = 1;
272 return (-1);
273 }
274 else if (count == 0)
275 gif_eof = 1;
276 else if (fread(buf, 1, count, fp) < count)
277 {
278 gif_eof = 1;
279 return (-1);
280 }
281 else
282 gif_eof = 0;
283
284 return (count);
285 }
286
287
288 /*
289 * 'gif_get_code()' - Get a LZW code from the file...
290 */
291
292 static int /* O - LZW code */
293 gif_get_code(FILE *fp, /* I - File to read from */
294 int code_size, /* I - Size of code in bits */
295 int first_time) /* I - 1 = first time, 0 = not first time */
296 {
297 unsigned i, j, /* Looping vars */
298 ret; /* Return value */
299 int count; /* Number of bytes read */
300 static unsigned char buf[280]; /* Input buffer */
301 static unsigned curbit, /* Current bit */
302 lastbit, /* Last bit in buffer */
303 done, /* Done with this buffer? */
304 last_byte; /* Last byte in buffer */
305 static const unsigned char bits[8] = /* Bit masks for codes */
306 {
307 0x01, 0x02, 0x04, 0x08,
308 0x10, 0x20, 0x40, 0x80
309 };
310
311
312 if (first_time)
313 {
314 /*
315 * Just initialize the input buffer...
316 */
317
318 curbit = 0;
319 lastbit = 0;
320 last_byte = 0;
321 done = 0;
322
323 return (0);
324 }
325
326 if ((curbit + code_size) >= lastbit)
327 {
328 /*
329 * Don't have enough bits to hold the code...
330 */
331
332 if (done)
333 return (-1); /* Sorry, no more... */
334
335 /*
336 * Move last two bytes to front of buffer...
337 */
338
339 if (last_byte > 1)
340 {
341 buf[0] = buf[last_byte - 2];
342 buf[1] = buf[last_byte - 1];
343 last_byte = 2;
344 }
345 else if (last_byte == 1)
346 {
347 buf[0] = buf[last_byte - 1];
348 last_byte = 1;
349 }
350
351 /*
352 * Read in another buffer...
353 */
354
355 if ((count = gif_get_block (fp, buf + last_byte)) <= 0)
356 {
357 /*
358 * Whoops, no more data!
359 */
360
361 done = 1;
362 return (-1);
363 }
364
365 /*
366 * Update buffer state...
367 */
368
369 curbit = (curbit - lastbit) + 8 * last_byte;
370 last_byte += count;
371 lastbit = last_byte * 8;
372 }
373
374 ret = 0;
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 */
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 */
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 (!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 */
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
614 if (sp > stack)
615 return (*--sp);
616
617 while ((code = gif_get_code (fp, code_size, 0)) >= 0)
618 {
619 if (code == clear_code)
620 {
621 for (i = 0; i < clear_code; i ++)
622 {
623 table[0][i] = 0;
624 table[1][i] = i;
625 }
626
627 for (; i < 4096; i ++)
628 table[0][i] = table[1][i] = 0;
629
630 code_size = set_code_size + 1;
631 max_code_size = 2 * clear_code;
632 max_code = clear_code + 2;
633
634 sp = stack;
635
636 firstcode = oldcode = gif_get_code(fp, code_size, 0);
637
638 return (firstcode);
639 }
640 else if (code == end_code)
641 {
642 unsigned char buf[260];
643
644
645 if (!gif_eof)
646 while (gif_get_block(fp, buf) > 0);
647
648 return (-2);
649 }
650
651 incode = code;
652
653 if (code >= max_code)
654 {
655 *sp++ = firstcode;
656 code = oldcode;
657 }
658
659 while (code >= clear_code)
660 {
661 *sp++ = table[1][code];
662 if (code == table[0][code])
663 return (255);
664
665 code = table[0][code];
666 }
667
668 *sp++ = firstcode = table[1][code];
669 code = max_code;
670
671 if (code < 4096)
672 {
673 table[0][code] = oldcode;
674 table[1][code] = firstcode;
675 max_code ++;
676
677 if (max_code >= max_code_size && max_code_size < 4096)
678 {
679 max_code_size *= 2;
680 code_size ++;
681 }
682 }
683
684 oldcode = incode;
685
686 if (sp > stack)
687 return (*--sp);
688 }
689
690 return (code);
691 }
692
693
694 /*
695 * End of "$Id: image-gif.c 6649 2007-07-11 21:46:42Z mike $".
696 */