]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/image-gif.c
Merge changes from CUPS 1.5.1-r9875.
[thirdparty/cups.git] / filter / image-gif.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: image-gif.c 7720 2008-07-11 22:46:21Z mike $"
ef416fc2 3 *
321d8d57 4 * GIF image routines for CUPS.
ef416fc2 5 *
321d8d57 6 * Copyright 2007-2011 by Apple Inc.
c0e1af83 7 * Copyright 1993-2007 by Easy Software Products.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
ef416fc2 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
839a51c8 40#define GIF_MAX_BITS 12
ef416fc2 41
42typedef cups_ib_t gif_cmap_t[256][4];
43typedef short gif_table_t[4096];
44
45
46/*
47 * Local globals...
48 */
49
50static int gif_eof = 0; /* Did we hit EOF? */
51
52
53/*
54 * Local functions...
55 */
56
57static int gif_get_block(FILE *fp, unsigned char *buffer);
58static int gif_get_code (FILE *fp, int code_size, int first_time);
59static int gif_read_cmap(FILE *fp, int ncolors, gif_cmap_t cmap,
60 int *gray);
61static int gif_read_image(FILE *fp, cups_image_t *img, gif_cmap_t cmap,
62 int interlace);
63static 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
70int /* O - Read status */
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 :
f301802f 215 for (i = ncolors - 1; i >= 0; i --)
216 cupsImageRGBToRGB(cmap[i], cmap[i], 1);
ef416fc2 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 {
c0e1af83 241 fprintf(stderr, "DEBUG: Bad GIF image dimensions: %dx%d\n",
ef416fc2 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
259static int /* O - Number characters read */
260gif_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
293static int /* O - LZW code */
294gif_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
771bd8cb 356 if ((count = gif_get_block(fp, buf + last_byte)) <= 0)
ef416fc2 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
ef416fc2 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
390static int /* O - -1 on error, 0 on success */
391gif_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
438static int /* I - 0 = success, -1 = failure */
439gif_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
321d8d57 465 if (!pixels)
91c84a35
MS
466 return (-1);
467
321d8d57 468 if (code_size > GIF_MAX_BITS || gif_read_lzw(fp, 1, code_size) < 0)
91c84a35
MS
469 {
470 free(pixels);
ef416fc2 471 return (-1);
91c84a35 472 }
ef416fc2 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
527static int /* I - Byte from stream */
528gif_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 /*
771bd8cb 585 * Wipe the decompressor table (already mostly 0 due to the calloc above...)
ef416fc2 586 */
587
588 fresh = 1;
589
771bd8cb 590 for (i = 1; i < clear_code; i ++)
ef416fc2 591 table[1][i] = i;
ef416fc2 592
593 sp = stack;
594
595 return (0);
596 }
597 else if (fresh)
598 {
599 fresh = 0;
600
601 do
771bd8cb 602 {
ef416fc2 603 firstcode = oldcode = gif_get_code(fp, code_size, 0);
771bd8cb 604 }
ef416fc2 605 while (firstcode == clear_code);
606
771bd8cb 607 return (firstcode & 255);
ef416fc2 608 }
1f0275e3
MS
609 else if (!table)
610 return (0);
ef416fc2 611
612 if (sp > stack)
771bd8cb 613 return ((*--sp) & 255);
ef416fc2 614
771bd8cb 615 while ((code = gif_get_code(fp, code_size, 0)) >= 0)
ef416fc2 616 {
617 if (code == clear_code)
618 {
771bd8cb
MS
619 /*
620 * Clear/reset the compression table...
621 */
ef416fc2 622
771bd8cb
MS
623 memset(table, 0, 2 * sizeof(gif_table_t));
624 for (i = 1; i < clear_code; i ++)
625 table[1][i] = i;
ef416fc2 626
627 code_size = set_code_size + 1;
628 max_code_size = 2 * clear_code;
629 max_code = clear_code + 2;
630
631 sp = stack;
632
633 firstcode = oldcode = gif_get_code(fp, code_size, 0);
634
771bd8cb 635 return (firstcode & 255);
ef416fc2 636 }
771bd8cb 637 else if (code == end_code || code > max_code)
ef416fc2 638 {
771bd8cb 639 unsigned char buf[260]; /* Block buffer */
ef416fc2 640
641 if (!gif_eof)
642 while (gif_get_block(fp, buf) > 0);
643
644 return (-2);
645 }
646
647 incode = code;
648
771bd8cb 649 if (code == max_code)
ef416fc2 650 {
771bd8cb
MS
651 if (sp < (stack + 8192))
652 *sp++ = firstcode;
653
654 code = oldcode;
ef416fc2 655 }
656
771bd8cb 657 while (code >= clear_code && sp < (stack + 8192))
ef416fc2 658 {
659 *sp++ = table[1][code];
660 if (code == table[0][code])
661 return (255);
662
663 code = table[0][code];
664 }
665
771bd8cb
MS
666 if (sp < (stack + 8192))
667 *sp++ = firstcode = table[1][code];
668
669 code = max_code;
ef416fc2 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)
771bd8cb 687 return ((*--sp) & 255);
ef416fc2 688 }
689
771bd8cb 690 return (code & 255);
ef416fc2 691}
692
693
694/*
b19ccc9e 695 * End of "$Id: image-gif.c 7720 2008-07-11 22:46:21Z mike $".
ef416fc2 696 */