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