]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/image-gif.c
Load cups into easysw/current.
[thirdparty/cups.git] / filter / image-gif.c
1 /*
2 * "$Id: image-gif.c 4741 2005-10-02 04:25:52Z mike $"
3 *
4 * GIF image routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1993-2005 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 break;
224 }
225
226 img->colorspace = primary;
227 }
228
229 if (lut)
230 {
231 bpp = cupsImageGetDepth(img);
232
233 for (i = ncolors - 1; i >= 0; i --)
234 cupsImageLut(cmap[i], bpp, lut);
235 }
236
237 img->xsize = (buf[5] << 8) | buf[4];
238 img->ysize = (buf[7] << 8) | buf[6];
239
240 /*
241 * Check the dimensions of the image; since the dimensions are
242 * a 16-bit integer we just need to check for 0...
243 */
244
245 if (img->xsize == 0 || img->ysize == 0)
246 {
247 fprintf(stderr, "ERROR: Bad GIF image dimensions: %dx%d\n",
248 img->xsize, img->ysize);
249 fclose(fp);
250 return (1);
251 }
252
253 i = gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE);
254 fclose(fp);
255 return (i);
256 }
257 }
258 }
259
260
261 /*
262 * 'gif_get_block()' - Read a GIF data block...
263 */
264
265 static int /* O - Number characters read */
266 gif_get_block(FILE *fp, /* I - File to read from */
267 unsigned char *buf) /* I - Input buffer */
268 {
269 int count; /* Number of character to read */
270
271
272 /*
273 * Read the count byte followed by the data from the file...
274 */
275
276 if ((count = getc(fp)) == EOF)
277 {
278 gif_eof = 1;
279 return (-1);
280 }
281 else if (count == 0)
282 gif_eof = 1;
283 else if (fread(buf, 1, count, fp) < count)
284 {
285 gif_eof = 1;
286 return (-1);
287 }
288 else
289 gif_eof = 0;
290
291 return (count);
292 }
293
294
295 /*
296 * 'gif_get_code()' - Get a LZW code from the file...
297 */
298
299 static int /* O - LZW code */
300 gif_get_code(FILE *fp, /* I - File to read from */
301 int code_size, /* I - Size of code in bits */
302 int first_time) /* I - 1 = first time, 0 = not first time */
303 {
304 unsigned i, j, /* Looping vars */
305 ret; /* Return value */
306 int count; /* Number of bytes read */
307 static unsigned char buf[280]; /* Input buffer */
308 static unsigned curbit, /* Current bit */
309 lastbit, /* Last bit in buffer */
310 done, /* Done with this buffer? */
311 last_byte; /* Last byte in buffer */
312 static const unsigned char bits[8] = /* Bit masks for codes */
313 {
314 0x01, 0x02, 0x04, 0x08,
315 0x10, 0x20, 0x40, 0x80
316 };
317
318
319 if (first_time)
320 {
321 /*
322 * Just initialize the input buffer...
323 */
324
325 curbit = 0;
326 lastbit = 0;
327 last_byte = 0;
328 done = 0;
329
330 return (0);
331 }
332
333 if ((curbit + code_size) >= lastbit)
334 {
335 /*
336 * Don't have enough bits to hold the code...
337 */
338
339 if (done)
340 return (-1); /* Sorry, no more... */
341
342 /*
343 * Move last two bytes to front of buffer...
344 */
345
346 if (last_byte > 1)
347 {
348 buf[0] = buf[last_byte - 2];
349 buf[1] = buf[last_byte - 1];
350 last_byte = 2;
351 }
352 else if (last_byte == 1)
353 {
354 buf[0] = buf[last_byte - 1];
355 last_byte = 1;
356 }
357
358 /*
359 * Read in another buffer...
360 */
361
362 if ((count = gif_get_block (fp, buf + last_byte)) <= 0)
363 {
364 /*
365 * Whoops, no more data!
366 */
367
368 done = 1;
369 return (-1);
370 }
371
372 /*
373 * Update buffer state...
374 */
375
376 curbit = (curbit - lastbit) + 8 * last_byte;
377 last_byte += count;
378 lastbit = last_byte * 8;
379 }
380
381 ret = 0;
382 for (ret = 0, i = curbit + code_size - 1, j = code_size;
383 j > 0;
384 i --, j --)
385 ret = (ret << 1) | ((buf[i / 8] & bits[i & 7]) != 0);
386
387 curbit += code_size;
388
389 return ret;
390 }
391
392
393 /*
394 * 'gif_read_cmap()' - Read the colormap from a GIF file...
395 */
396
397 static int /* O - -1 on error, 0 on success */
398 gif_read_cmap(FILE *fp, /* I - File to read from */
399 int ncolors, /* I - Number of colors in file */
400 gif_cmap_t cmap, /* O - Colormap information */
401 int *gray) /* IO - Is the image grayscale? */
402 {
403 int i; /* Looping var */
404
405
406 /*
407 * Read the colormap...
408 */
409
410 for (i = 0; i < ncolors; i ++)
411 if (fread(cmap[i], 3, 1, fp) < 1)
412 return (-1);
413
414 /*
415 * Check to see if the colormap is a grayscale ramp...
416 */
417
418 for (i = 0; i < ncolors; i ++)
419 if (cmap[i][0] != cmap[i][1] || cmap[i][1] != cmap[i][2])
420 break;
421
422 if (i == ncolors)
423 {
424 *gray = 1;
425 return (0);
426 }
427
428 /*
429 * If this needs to be a grayscale image, convert the RGB values to
430 * luminance values...
431 */
432
433 if (*gray)
434 for (i = 0; i < ncolors; i ++)
435 cmap[i][0] = (cmap[i][0] * 31 + cmap[i][1] * 61 + cmap[i][2] * 8) / 100;
436
437 return (0);
438 }
439
440
441 /*
442 * 'gif_read_image()' - Read a GIF image stream...
443 */
444
445 static int /* I - 0 = success, -1 = failure */
446 gif_read_image(FILE *fp, /* I - Input file */
447 cups_image_t *img, /* I - cupsImage pointer */
448 gif_cmap_t cmap, /* I - Colormap */
449 int interlace) /* I - Non-zero = interlaced image */
450 {
451 unsigned char code_size; /* Code size */
452 cups_ib_t *pixels, /* Pixel buffer */
453 *temp; /* Current pixel */
454 int xpos, /* Current X position */
455 ypos, /* Current Y position */
456 pass; /* Current pass */
457 int pixel; /* Current pixel */
458 int bpp; /* Bytes per pixel */
459 static const int xpasses[4] = /* X interleaving */
460 { 8, 8, 4, 2 },
461 ypasses[5] = /* Y interleaving */
462 { 0, 4, 2, 1, 999999 };
463
464
465 bpp = cupsImageGetDepth(img);
466 pixels = calloc(bpp, img->xsize);
467 xpos = 0;
468 ypos = 0;
469 pass = 0;
470 code_size = getc(fp);
471
472 if (gif_read_lzw(fp, 1, code_size) < 0)
473 return (-1);
474
475 temp = pixels;
476 while ((pixel = gif_read_lzw(fp, 0, code_size)) >= 0)
477 {
478 switch (bpp)
479 {
480 case 4 :
481 temp[3] = cmap[pixel][3];
482 case 3 :
483 temp[2] = cmap[pixel][2];
484 case 2 :
485 temp[1] = cmap[pixel][1];
486 default :
487 temp[0] = cmap[pixel][0];
488 }
489
490 xpos ++;
491 temp += bpp;
492 if (xpos == img->xsize)
493 {
494 _cupsImagePutRow(img, 0, ypos, img->xsize, pixels);
495
496 xpos = 0;
497 temp = pixels;
498
499 if (interlace)
500 {
501 ypos += xpasses[pass];
502
503 if (ypos >= img->ysize)
504 {
505 pass ++;
506
507 ypos = ypasses[pass];
508 }
509 }
510 else
511 ypos ++;
512 }
513
514 if (ypos >= img->ysize)
515 break;
516 }
517
518 free(pixels);
519
520 return (0);
521 }
522
523
524 /*
525 * 'gif_read_lzw()' - Read a byte from the LZW stream...
526 */
527
528 static int /* I - Byte from stream */
529 gif_read_lzw(FILE *fp, /* I - File to read from */
530 int first_time, /* I - 1 = first time, 0 = not first time */
531 int input_code_size) /* I - Code size in bits */
532 {
533 int i, /* Looping var */
534 code, /* Current code */
535 incode; /* Input code */
536 static short fresh = 0, /* 1 = empty buffers */
537 code_size, /* Current code size */
538 set_code_size, /* Initial code size set */
539 max_code, /* Maximum code used */
540 max_code_size, /* Maximum code size */
541 firstcode, /* First code read */
542 oldcode, /* Last code read */
543 clear_code, /* Clear code for LZW input */
544 end_code, /* End code for LZW input */
545 *stack = NULL, /* Output stack */
546 *sp; /* Current stack pointer */
547 static gif_table_t *table = NULL; /* String table */
548
549
550 if (first_time)
551 {
552 /*
553 * Setup LZW state...
554 */
555
556 set_code_size = input_code_size;
557 code_size = set_code_size + 1;
558 clear_code = 1 << set_code_size;
559 end_code = clear_code + 1;
560 max_code_size = 2 * clear_code;
561 max_code = clear_code + 2;
562
563 /*
564 * Allocate memory for buffers...
565 */
566
567 if (table == NULL)
568 table = calloc(2, sizeof(gif_table_t));
569
570 if (table == NULL)
571 return (-1);
572
573 if (stack == NULL)
574 stack = calloc(8192, sizeof(short));
575
576 if (stack == NULL)
577 return (-1);
578
579 /*
580 * Initialize input buffers...
581 */
582
583 gif_get_code(fp, 0, 1);
584
585 /*
586 * Wipe the decompressor table...
587 */
588
589 fresh = 1;
590
591 for (i = 0; i < clear_code; i ++)
592 {
593 table[0][i] = 0;
594 table[1][i] = i;
595 }
596
597 for (; i < 4096; i ++)
598 table[0][i] = table[1][0] = 0;
599
600 sp = stack;
601
602 return (0);
603 }
604 else if (fresh)
605 {
606 fresh = 0;
607
608 do
609 firstcode = oldcode = gif_get_code(fp, code_size, 0);
610 while (firstcode == clear_code);
611
612 return (firstcode);
613 }
614
615 if (sp > stack)
616 return (*--sp);
617
618 while ((code = gif_get_code (fp, code_size, 0)) >= 0)
619 {
620 if (code == clear_code)
621 {
622 for (i = 0; i < clear_code; i ++)
623 {
624 table[0][i] = 0;
625 table[1][i] = i;
626 }
627
628 for (; i < 4096; i ++)
629 table[0][i] = table[1][i] = 0;
630
631 code_size = set_code_size + 1;
632 max_code_size = 2 * clear_code;
633 max_code = clear_code + 2;
634
635 sp = stack;
636
637 firstcode = oldcode = gif_get_code(fp, code_size, 0);
638
639 return (firstcode);
640 }
641 else if (code == end_code)
642 {
643 unsigned char buf[260];
644
645
646 if (!gif_eof)
647 while (gif_get_block(fp, buf) > 0);
648
649 return (-2);
650 }
651
652 incode = code;
653
654 if (code >= max_code)
655 {
656 *sp++ = firstcode;
657 code = oldcode;
658 }
659
660 while (code >= clear_code)
661 {
662 *sp++ = table[1][code];
663 if (code == table[0][code])
664 return (255);
665
666 code = table[0][code];
667 }
668
669 *sp++ = firstcode = table[1][code];
670 code = max_code;
671
672 if (code < 4096)
673 {
674 table[0][code] = oldcode;
675 table[1][code] = firstcode;
676 max_code ++;
677
678 if (max_code >= max_code_size && max_code_size < 4096)
679 {
680 max_code_size *= 2;
681 code_size ++;
682 }
683 }
684
685 oldcode = incode;
686
687 if (sp > stack)
688 return (*--sp);
689 }
690
691 return (code);
692 }
693
694
695 /*
696 * End of "$Id: image-gif.c 4741 2005-10-02 04:25:52Z mike $".
697 */