1/*---------------------------------------------------------------------------*
2 |              PDFlib - A library for generating PDF on the fly             |
3 +---------------------------------------------------------------------------+
4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. |
5 +---------------------------------------------------------------------------+
6 |                                                                           |
7 |    This software is subject to the PDFlib license. It is NOT in the       |
8 |    public domain. Extended versions and commercial licenses are           |
9 |    available, please check http://www.pdflib.com.                         |
10 |                                                                           |
11 *---------------------------------------------------------------------------*/
12
13/* $Id: p_gif.c 14574 2005-10-29 16:27:43Z bonefish $
14 *
15 * GIF processing for PDFlib
16 *
17 */
18
19#include "p_intern.h"
20#include "p_image.h"
21
22#ifndef PDF_GIF_SUPPORTED
23
24pdc_bool
25pdf_is_GIF_file(PDF *p, pdc_file *fp)
26{
27    (void) p;
28    (void) fp;
29
30    return pdc_false;
31}
32
33int
34pdf_process_GIF_data(
35    PDF *p,
36    int imageslot)
37{
38    (void) imageslot;
39
40    pdc_warning(p->pdc, PDF_E_UNSUPP_IMAGE, "GIF", 0, 0, 0);
41    return -1;
42}
43
44#else
45
46#define LOCALCOLORMAP		0x80
47#define BitSet(byteval, bitval)	(((byteval) & (bitval)) == (bitval))
48
49static int ReadColorMap(pdc_core *pdc, pdc_file *fp,
50                        int number, pdf_colormap *buffer);
51static int DoExtension(PDF *p, pdf_image *image, int label);
52static int GetDataBlock(PDF *p, pdf_image *image, unsigned char  *buf);
53
54static void
55pdf_data_source_GIF_init(PDF *p, PDF_data_source *src)
56{
57    pdf_image		*image = (pdf_image *) src->private_data;
58
59    src->buffer_length	= 260;	/* max. GIF "data sub-block" length */
60
61    src->buffer_start	= (pdc_byte*) pdc_malloc(p->pdc, src->buffer_length,
62				"pdf_data_source_GIF_init");
63    src->bytes_available= 0;
64    src->next_byte	= src->buffer_start;
65
66    /* init the LZW transformation vars */
67    image->info.gif.c_size = 9;		/* initial code size	*/
68    image->info.gif.t_size = 257;	/* initial "table" size	*/
69    image->info.gif.i_buff = 0;		/* input buffer		*/
70    image->info.gif.i_bits = 0;		/* input buffer empty	*/
71    image->info.gif.o_bits = 0;		/* output buffer empty	*/
72} /* pdf_data_source_GIF_init */
73
74static pdc_bool
75pdf_data_source_GIF_fill(PDF *p, PDF_data_source *src)
76{
77#define c_size	image->info.gif.c_size
78#define t_size	image->info.gif.t_size
79#define i_buff	image->info.gif.i_buff
80#define i_bits	image->info.gif.i_bits
81#define o_buff	image->info.gif.o_buff
82#define o_bits	image->info.gif.o_bits
83
84    pdf_image *		image = (pdf_image *) src->private_data;
85    pdc_file *		fp = image->fp;
86    int			n_bytes = pdc_fgetc(fp);
87                                 /* # of bytes to read	*/
88    unsigned char *	o_curr = src->buffer_start;
89    int			c_mask = (1 << c_size) - 1;
90    pdc_bool		flag13 = pdc_false;
91
92    src->bytes_available = 0;
93
94    if (n_bytes == EOF)
95    {
96        const char *stemp = pdc_errprintf(p->pdc, "%s", image->filename);
97	pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF", stemp, 0, 0);
98    }
99
100    if (n_bytes == 0)
101	return pdc_false;
102
103    for (/* */ ; /* */ ; /* */)
104    {
105	int w_bits = c_size;	/* number of bits to write */
106	int code;
107
108	/* get at least c_size bits into i_buff	*/
109	while (i_bits < c_size)
110	{
111	    if (n_bytes-- == 0)
112	    {
113		src->bytes_available = (size_t) (o_curr - src->buffer_start);
114		return pdc_true;
115	    }
116            /* EOF will be caught later */
117            i_buff |= pdc_fgetc(fp) << i_bits;
118	    i_bits += 8;
119	}
120	code = i_buff & c_mask;
121	i_bits -= c_size;
122	i_buff >>= c_size;
123
124	if (flag13 && code != 256 && code != 257)
125	{
126            const char *stemp = pdc_errprintf(p->pdc, "%s", image->filename);
127            pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF", stemp, 0, 0);
128	}
129
130	if (o_bits > 0)
131	{
132	    o_buff |= code >> (c_size - 8 + o_bits);
133	    w_bits -= 8 - o_bits;
134	    *(o_curr++) = (unsigned char) o_buff;
135	}
136	if (w_bits >= 8)
137	{
138	    w_bits -= 8;
139	    *(o_curr++) = (unsigned char) (code >> w_bits);
140	}
141	o_bits = w_bits;
142	if (o_bits > 0)
143	    o_buff = code << (8 - o_bits);
144
145	++t_size;
146	if (code == 256)	/* clear code */
147	{
148	    c_size = 9;
149	    c_mask = (1 << c_size) - 1;
150	    t_size = 257;
151	    flag13 = pdc_false;
152	}
153
154	if (code == 257)	/* end code */
155	{
156	    src->bytes_available = (size_t) (o_curr - src->buffer_start);
157	    return pdc_true;
158	}
159
160	if (t_size == (1 << c_size))
161	{
162	    if (++c_size > 12)
163	    {
164		--c_size;
165		flag13 = pdc_true;
166	    }
167	    else
168		c_mask = (1 << c_size) - 1;
169	}
170    } /* for (;;) */
171
172#undef	c_size
173#undef	t_size
174#undef	i_buff
175#undef	i_bits
176#undef	o_buff
177#undef	o_bits
178} /* pdf_data_source_GIF_fill */
179
180static void
181pdf_data_source_GIF_terminate(PDF *p, PDF_data_source *src)
182{
183    pdc_free(p->pdc, (void *) src->buffer_start);
184}
185
186#define PDF_STRING_GIF  "\107\111\106"
187#define PDF_STRING_87a  "\070\067\141"
188#define PDF_STRING_89a  "\070\071\141"
189
190pdc_bool
191pdf_is_GIF_file(PDF *p, pdc_file *fp)
192{
193    unsigned char buf[3];
194
195    (void) p;
196
197    if (!PDC_OK_FREAD(fp, buf, 3) ||
198        strncmp((const char *) buf, PDF_STRING_GIF, 3) != 0) {
199        pdc_fseek(fp, 0L, SEEK_SET);
200        return pdc_false;
201    }
202    return pdc_true;
203}
204
205int
206pdf_process_GIF_data(
207    PDF *p,
208    int imageslot)
209{
210    static const char fn[] = "pdf_process_GIF_data";
211    unsigned char	buf[16];
212    char	c;
213    int		imageCount = 0;
214    char	version[4];
215    int         errcode = 0;
216    pdf_image	*image;
217    pdf_colorspace cs;
218    pdf_colormap colormap;
219    int slot;
220
221    image = &p->images[imageslot];
222
223
224    /* we invert this flag later */
225    if (image->ignoremask)
226	image->transparent = pdc_true;
227
228    if (image->page == pdc_undef)
229        image->page = 1;
230
231    /* Error reading magic number or not a GIF file */
232    if (pdf_is_GIF_file(p, image->fp) == pdc_false) {
233        errcode = PDC_E_IO_BADFORMAT;
234        goto PDF_GIF_ERROR;
235    }
236
237    /* Version number */
238    if (! PDC_OK_FREAD(image->fp, buf, 3)) {
239        errcode = PDC_E_IO_BADFORMAT;
240        goto PDF_GIF_ERROR;
241    }
242    strncpy(version, (const char *) buf, 3);
243    version[3] = '\0';
244    if ((strcmp(version, PDF_STRING_87a) != 0) &&
245        (strcmp(version, PDF_STRING_89a) != 0)) {
246        errcode = PDC_E_IO_BADFORMAT;
247        goto PDF_GIF_ERROR;
248    }
249
250    /* Failed to read screen descriptor */
251    if (! PDC_OK_FREAD(image->fp, buf, 7)) {
252        errcode = PDC_E_IO_BADFORMAT;
253        goto PDF_GIF_ERROR;
254    }
255
256    cs.type = Indexed;
257    /* size of the global color table */
258    cs.val.indexed.palette_size = 2 << (buf[4] & 0x07);
259    cs.val.indexed.base = DeviceRGB;
260    cs.val.indexed.colormap = &colormap;
261    cs.val.indexed.colormap_id = PDC_BAD_ID;
262
263    if (BitSet(buf[4], LOCALCOLORMAP)) {	/* Global Colormap */
264        if (ReadColorMap(p->pdc, image->fp,
265                         cs.val.indexed.palette_size, &colormap)) {
266            errcode = PDF_E_IMAGE_COLORMAP;
267            goto PDF_GIF_ERROR;
268	}
269    }
270
271    /* translate the aspect ratio to PDFlib notation */
272    if (buf[6] != 0) {
273	image->dpi_x = -(buf[6] + ((float) 15.0)) / ((float) 64.0);
274	image->dpi_y = (float) -1.0;
275    }
276
277    for (/* */ ; /* */ ; /* */) {
278	/* EOF / read error in image data */
279        if (!PDC_OK_FREAD(image->fp, &c, 1)) {
280            errcode = PDC_E_IO_NODATA;
281            goto PDF_GIF_ERROR;
282	}
283
284#define PDF_SEMICOLON		((char) 0x3b)		/* ASCII ';'  */
285
286	if (c == PDF_SEMICOLON) {		/* GIF terminator */
287	    /* Not enough images found in file */
288	    if (imageCount < image->page) {
289                if (!imageCount)
290                    errcode = PDF_E_IMAGE_CORRUPT;
291                else
292                    errcode = PDF_E_IMAGE_NOPAGE;
293                goto PDF_GIF_ERROR;
294	    }
295	    break;
296	}
297
298#define PDF_EXCLAM		((char) 0x21)		/* ASCII '!'  */
299
300	if (c == PDF_EXCLAM) { 	/* Extension */
301            if (!PDC_OK_FREAD(image->fp, &c, 1)) {
302		/* EOF / read error on extension function code */
303                errcode = PDC_E_IO_NODATA;
304                goto PDF_GIF_ERROR;
305	    }
306	    DoExtension(p, image, (int) c);
307	    continue;
308	}
309
310#define PDF_COMMA		((char) 0x2c)		/* ASCII ','  */
311
312	if (c != PDF_COMMA) {		/* Not a valid start character */
313	    /* Bogus character, ignoring */
314	    continue;
315	}
316
317	++imageCount;
318
319        if (! PDC_OK_FREAD(image->fp, buf, 9)) {
320	    /* Couldn't read left/top/width/height */
321            errcode = PDC_E_IO_NODATA;
322            goto PDF_GIF_ERROR;
323	}
324
325	image->components	= 1;
326	image->bpc		= 8;
327        image->width            = (float) pdc_get_le_ushort(&buf[4]);
328        image->height           = (float) pdc_get_le_ushort(&buf[6]);
329
330	if (image->imagemask)
331	{
332	    if (p->compatibility <= PDC_1_3) {
333		errcode = PDF_E_IMAGE_MASK1BIT13;
334		goto PDF_GIF_ERROR;
335	    } else {
336		/* images with more than one bit will be written as /SMask,
337		 * and don't require an /ImageMask entry.
338		 */
339		image->imagemask = pdc_false;
340	    }
341	    image->colorspace = DeviceGray;
342	}
343
344#define INTERLACE		0x40
345	if (BitSet(buf[8], INTERLACE)) {
346            errcode = PDF_E_GIF_INTERLACED;
347            goto PDF_GIF_ERROR;
348	}
349
350	if (BitSet(buf[8], LOCALCOLORMAP)) {
351            if (ReadColorMap(p->pdc, image->fp,
352                             cs.val.indexed.palette_size, &colormap))
353	    {
354                errcode = PDF_E_IMAGE_COLORMAP;
355                goto PDF_GIF_ERROR;
356	    }
357	}
358
359	/* read the "LZW initial code size".
360	*/
361        if (!PDC_OK_FREAD(image->fp, buf, 1)) {
362            errcode = PDC_E_IO_NODATA;
363            goto PDF_GIF_ERROR;
364	}
365        if (buf[0] != 8) {
366            if (imageCount > 1)
367                errcode = PDF_E_IMAGE_NOPAGE;
368            else
369                errcode = PDF_E_GIF_LZWSIZE;
370            goto PDF_GIF_ERROR;
371	}
372
373	if (imageCount == image->page)
374	    break;
375    }
376
377    image->src.init		= pdf_data_source_GIF_init;
378    image->src.fill		= pdf_data_source_GIF_fill;
379    image->src.terminate	= pdf_data_source_GIF_terminate;
380    image->src.private_data	= (void *) image;
381
382    image->compression		= lzw;
383    image->use_raw  		= pdc_true;
384
385    image->params = (char *) pdc_malloc(p->pdc, PDF_MAX_PARAMSTRING, fn);
386    strcpy(image->params, "/EarlyChange 0");
387
388    image->in_use               = pdc_true;             /* mark slot as used */
389
390	slot = pdf_add_colorspace(p, &cs, pdc_false);
391	image->colorspace = (pdf_colorspacetype) slot;
392
393
394
395    pdf_put_image(p, imageslot, pdc_true);
396
397    return imageslot;
398
399    PDF_GIF_ERROR:
400    {
401        const char *stemp = pdc_errprintf(p->pdc, "%s", image->filename);
402        switch (errcode)
403        {
404            case PDC_E_IO_NODATA:
405            case PDF_E_IMAGE_COLORMAP:
406            case PDF_E_GIF_INTERLACED:
407            case PDF_E_GIF_LZWSIZE:
408		pdc_set_errmsg(p->pdc, errcode, stemp, 0, 0, 0);
409		break;
410
411            case PDC_E_IO_BADFORMAT:
412		pdc_set_errmsg(p->pdc, errcode, stemp, "GIF", 0, 0);
413		break;
414
415            case PDF_E_IMAGE_CORRUPT:
416		pdc_set_errmsg(p->pdc, errcode, "GIF", stemp, 0, 0);
417		break;
418
419            case PDF_E_IMAGE_NOPAGE:
420		pdc_set_errmsg(p->pdc, errcode,
421		    pdc_errprintf(p->pdc, "%d", image->page), "GIF", stemp, 0);
422		break;
423
424	    case 0: 		/* error code and message already set */
425		break;
426        }
427    }
428
429    if (image->verbose)
430	pdc_error(p->pdc, -1, 0, 0, 0, 0);
431
432    return -1;
433} /* pdf_open_GIF_data */
434
435static int
436ReadColorMap(pdc_core *pdc, pdc_file *fp, int number, pdf_colormap *buffer)
437{
438    int		i;
439    unsigned char	rgb[3];
440
441    (void) pdc;
442
443    for (i = 0; i < number; ++i) {
444        if (! PDC_OK_FREAD(fp, rgb, sizeof(rgb))) {
445	    return pdc_true;		/* yk: true == error */
446	}
447
448	(*buffer)[i][0] = rgb[0] ;
449	(*buffer)[i][1] = rgb[1] ;
450	(*buffer)[i][2] = rgb[2] ;
451    }
452    return pdc_false;			/* yk: false == ok.  */
453} /* ReadColorMap */
454
455static int
456DoExtension(PDF *p, pdf_image *image, int label)
457{
458    pdc_byte            buf[256];
459
460    switch ((unsigned char) label) {
461	case 0x01:		/* Plain Text Extension */
462	    break;
463
464	case 0xff:		/* Application Extension */
465	    break;
466
467	case 0xfe:		/* Comment Extension */
468	    while (GetDataBlock(p, image, (unsigned char*) buf) != 0) {
469		/* */
470	    }
471	    return pdc_false;
472
473	case 0xf9:		/* Graphic Control Extension */
474	    (void) GetDataBlock(p, image, (unsigned char*) buf);
475
476	    if ((buf[0] & 0x1) != 0) {
477		image->transparent = !image->transparent;
478		image->transval[0] = buf[3];
479	    }
480
481	    while (GetDataBlock(p, image, (unsigned char*) buf) != 0) {
482		    /* */ ;
483	    }
484	    return pdc_false;
485
486	default:
487	    break;
488    }
489
490    while (GetDataBlock(p, image, (unsigned char*) buf) != 0) {
491	    /* */ ;
492    }
493
494    return pdc_false;
495} /* DoExtension */
496
497static int
498GetDataBlock(PDF *p, pdf_image *image, unsigned char *buf)
499{
500    unsigned char	count;
501    pdc_file *fp = image->fp;
502
503    if ((!PDC_OK_FREAD(fp, &count, 1)) ||
504        ((count != 0) && (!PDC_OK_FREAD(fp, buf, count))))
505    {
506        const char *stemp = pdc_errprintf(p->pdc, "%s", image->filename);
507        pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "GIF", stemp, 0, 0);
508    }
509
510    return count;
511} /* GetDataBlock */
512
513#endif  /* PDF_GIF_SUPPORTED */
514