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_image.c 14574 2005-10-29 16:27:43Z bonefish $
14 *
15 * PDFlib image routines
16 *
17 */
18
19#define P_IMAGE_C
20
21#include "p_intern.h"
22#include "p_image.h"
23#include "p_font.h"
24
25/* must be kept in sync with the pdf_compression enum in p_intern.h */
26static const char *pdf_filter_names[] = {
27    "", "LZWDecode", "RunLengthDecode", "CCITTFaxDecode",
28    "DCTDecode", "FlateDecode", "JBIG2Decode"
29};
30
31static const char *pdf_short_filter_names[] = {
32    "", "LZW", "RL", "CCF", "DCT", "Fl", ""
33};
34
35static void
36pdf_init_image_struct(PDF *p, pdf_image *image)
37{
38    (void) p;
39
40    /********** option variables *************/
41    image->verbose      = pdc_true;
42    image->bitreverse   = pdc_false;
43    image->bpc          = pdc_undef;
44    image->components   = pdc_undef;
45    image->height_pixel = pdc_undef;
46    image->ignoremask   = pdc_false;
47    image->doinline     = pdc_false;
48    image->interpolate  = pdc_false;
49    image->invert       = pdc_false;
50    image->K            = 0;
51    image->imagemask    = pdc_false;
52    image->mask         = pdc_undef;
53    image->ri           = AutoIntent;
54    image->page         = 1;
55    image->reference    = pdf_ref_direct;
56    image->width_pixel  = pdc_undef;
57    /*****************************************/
58
59    image->transparent  = pdc_false;
60    image->compression	= none;
61    image->predictor	= pred_default;
62    image->in_use	= pdc_false;
63    image->fp           = (pdc_file *) NULL;
64    image->filename	= (char *) NULL;
65    image->params	= (char *) NULL;
66    image->dpi_x	= (float) 0;
67    image->dpi_y	= (float) 0;
68    image->strips	= 1;
69    image->rowsperstrip	= 1;
70    image->colorspace   = pdc_undef;
71    image->dochandle    = pdc_undef;        /* this means "not a PDI page" */
72    image->use_raw	= pdc_false;
73    image->transval[0]	= 0;
74    image->transval[1]	= 0;
75    image->transval[2]	= 0;
76    image->transval[3]	= 0;
77}
78
79void
80pdf_init_images(PDF *p)
81{
82    int im;
83
84    p->images_capacity = IMAGES_CHUNKSIZE;
85
86    p->images = (pdf_image *)
87    	pdc_malloc(p->pdc,
88	    sizeof(pdf_image) * p->images_capacity, "pdf_init_images");
89
90    for (im = 0; im < p->images_capacity; im++)
91	pdf_init_image_struct(p, &(p->images[im]));
92}
93
94void
95pdf_grow_images(PDF *p)
96{
97    int im;
98
99    p->images = (pdf_image *) pdc_realloc(p->pdc, p->images,
100	sizeof(pdf_image) * 2 * p->images_capacity, "pdf_grow_images");
101
102    for (im = p->images_capacity; im < 2 * p->images_capacity; im++)
103	pdf_init_image_struct(p, &(p->images[im]));
104
105    p->images_capacity *= 2;
106}
107
108void
109pdf_cleanup_image(PDF *p, int im)
110{
111    /* clean up parameter string if necessary */
112    if (p->images[im].params) {
113        pdc_free(p->pdc, p->images[im].params);
114        p->images[im].params = NULL;
115    }
116
117    if (p->images[im].filename) {
118        pdc_free(p->pdc, p->images[im].filename);
119        p->images[im].filename = NULL;
120    }
121
122    if (p->images[im].fp) {
123        pdc_fclose(p->images[im].fp);
124        p->images[im].fp = NULL;
125    }
126
127    /* free the image slot and prepare for next use */
128    pdf_init_image_struct(p, &(p->images[im]));
129}
130
131void
132pdf_cleanup_images(PDF *p)
133{
134    int im;
135
136    if (!p->images)
137	return;
138
139    /* Free images which the caller left open */
140
141    /* When we think of inter-document survival of images,
142    ** we MUST NOT FORGET that the current TIFF algorithm
143    ** depends on contiguous image slots for the image strips!
144    */
145    for (im = 0; im < p->images_capacity; im++)
146    {
147	pdf_image *img = &p->images[im];
148
149	if (img->in_use)		/* found used slot */
150	    pdf_cleanup_image(p, im);	/* free image descriptor */
151    }
152
153    pdc_free(p->pdc, p->images);
154    p->images = NULL;
155}
156
157void
158pdf_init_xobjects(PDF *p)
159{
160    int idx;
161
162    p->xobjects_number = 0;
163
164    if (p->xobjects == (pdf_xobject *) 0)
165    {
166	p->xobjects_capacity = XOBJECTS_CHUNKSIZE;
167
168	p->xobjects = (pdf_xobject *)
169	    pdc_malloc(p->pdc, sizeof(pdf_xobject) * p->xobjects_capacity,
170	    "pdf_init_xobjects");
171    }
172
173    for (idx = 0; idx < p->xobjects_capacity; idx++)
174	p->xobjects[idx].flags = 0;
175}
176
177int
178pdf_new_xobject(PDF *p, pdf_xobj_type type, pdc_id obj_id)
179{
180    static const char fn[] = "pdf_new_xobject";
181    int i, slot = p->xobjects_number++;
182
183    if (slot == p->xobjects_capacity)
184    {
185	p->xobjects = (pdf_xobject *) pdc_realloc(p->pdc, p->xobjects,
186	    sizeof(pdf_xobject) * 2 * p->xobjects_capacity, fn);
187
188	for (i = p->xobjects_capacity; i < 2 * p->xobjects_capacity; i++)
189	    p->xobjects[i].flags = 0;
190
191	p->xobjects_capacity *= 2;
192    }
193
194    if (obj_id == PDC_NEW_ID)
195	obj_id = pdc_begin_obj(p->out, PDC_NEW_ID);
196
197    p->xobjects[slot].obj_id = obj_id;
198    p->xobjects[slot].type = type;
199    p->xobjects[slot].flags = xobj_flag_used;
200
201    return slot;
202}
203
204void
205pdf_write_xobjects(PDF *p)
206{
207    if (p->xobjects_number > 0)
208    {
209	pdc_bool hit = pdc_false;
210	int i;
211
212	for (i = 0; i < p->xobjects_capacity; ++i)
213	{
214	    if (p->xobjects[i].flags & xobj_flag_write)
215	    {
216		if (!hit)
217		{
218		    pdc_puts(p->out, "/XObject");
219		    pdc_begin_dict(p->out);
220		    hit = pdc_true;
221		}
222
223		pdc_printf(p->out, "/I%d %ld 0 R\n", i, p->xobjects[i].obj_id);
224		p->xobjects[i].flags &= ~xobj_flag_write;
225	    }
226	}
227
228	if (hit)
229	    pdc_end_dict(p->out);
230    }
231}
232
233void
234pdf_cleanup_xobjects(PDF *p)
235{
236    if (p->xobjects) {
237	pdc_free(p->pdc, p->xobjects);
238	p->xobjects = NULL;
239    }
240}
241
242void
243pdf_put_inline_image(PDF *p, int im)
244{
245    pdf_image	*image;
246    pdc_matrix m;
247    PDF_data_source *src;
248    int		i;
249
250    image = &p->images[im];
251
252    /* Image object */
253
254    image->no = -1;
255
256    pdf__save(p);
257
258    pdc_scale_matrix(image->width, image->height, &m);
259
260    pdf_concat_raw(p, &m);
261
262    pdc_puts(p->out, "BI");
263
264    pdc_printf(p->out, "/W %d", (int) image->width);
265    pdc_printf(p->out, "/H %d", (int) image->height);
266
267    if (image->imagemask == pdc_true) {
268	pdc_puts(p->out, "/IM true");
269
270    } else {
271
272	pdc_printf(p->out, "/BPC %d", image->bpc);
273
274	switch (p->colorspaces[image->colorspace].type) {
275	    case DeviceGray:
276		pdc_printf(p->out, "/CS/G");
277		break;
278
279	    case DeviceRGB:
280		pdc_printf(p->out, "/CS/RGB");
281		break;
282
283	    case DeviceCMYK:
284		pdc_printf(p->out, "/CS/CMYK");
285		break;
286
287	    default:
288		pdc_error(p->pdc, PDF_E_INT_BADCS,
289		    pdc_errprintf(p->pdc, "%d", image->colorspace), 0, 0, 0);
290		break;
291	}
292    }
293
294    if (image->compression != none) {
295	pdc_printf(p->out, "/F/%s",
296		pdf_short_filter_names[image->compression]);
297    }
298
299    /* prepare precompressed (raw) image data */
300    if (image->use_raw &&
301        (image->params ||
302	 image->predictor != pred_default ||
303	 image->compression == ccitt)) {
304
305	pdc_printf(p->out, "/DP[<<");
306
307        /* write EarlyChange */
308        if (image->params)
309            pdc_puts(p->out, image->params);
310
311        if (image->compression == ccitt) {
312            if (image->K != 0)
313                pdc_printf(p->out, "/K %d", image->K);
314        }
315
316	if (image->compression == flate || image->compression == lzw) {
317	    if (image->predictor != pred_default) {
318		pdc_printf(p->out, "/Predictor %d", (int) image->predictor);
319		pdc_printf(p->out, "/Columns %d", (int) image->width);
320		if (image->bpc != 8)
321		    pdc_printf(p->out, "/BitsPerComponent %d", image->bpc);
322
323		if (image->components != 1)	/* 1 is default */
324		    pdc_printf(p->out, "/Colors %d", image->components);
325	    }
326	}
327
328	if (image->compression == ccitt) {
329	    if ((int) image->width != 1728)	/* CCITT default width */
330		pdc_printf(p->out, "/Columns %d", (int) image->width);
331
332	    pdc_printf(p->out, "/Rows %d", (int) fabs(image->height));
333	}
334	pdc_puts(p->out, ">>]");		/* DecodeParms dict and array */
335    }
336
337    if (image->invert) {
338	pdc_puts(p->out, "/D[1 0");
339	for (i = 1; i < image->components; i++)
340	    pdc_puts(p->out, " 1 0");
341	pdc_puts(p->out, "]");
342    }
343
344    if (image->ri != AutoIntent) {
345        pdc_printf(p->out, "/Intent/%s",
346            pdc_get_keyword(image->ri, gs_renderingintents));
347    }
348
349    if (image->interpolate) {
350        pdc_puts(p->out, "/I true");
351    }
352
353    pdc_puts(p->out, " ID\n");
354
355    /* Write the actual image data to the content stream */
356
357    src = &image->src;
358
359    /* We can't use pdf_copy_stream() here because it automatically
360     * generates a stream object, which is not correct for inline
361     * image data.
362     */
363    if (src->init)
364	src->init(p, src);
365
366    while (src->fill(p, src))
367	pdc_write(p->out, src->next_byte, src->bytes_available);
368
369    if (src->terminate)
370	src->terminate(p, src);
371
372    pdc_puts(p->out, "EI\n");
373
374    pdf__restore(p);
375
376    /* Do the equivalent of PDF_close_image() since the image handle
377     * cannot be re-used anyway.
378     */
379    pdf_cleanup_image(p, im);
380}
381
382void
383pdf_put_image(PDF *p, int im, pdc_bool firststrip)
384{
385    pdc_id	length_id;
386    pdf_image	*image;
387    int		i;
388
389    image = &p->images[im];
390
391    /* Images may also be written to the output before the first page */
392    if (PDF_GET_STATE(p) == pdf_state_page)
393	pdf_end_contents_section(p);
394
395    /* Image object */
396
397    image->no = pdf_new_xobject(p, image_xobject, PDC_NEW_ID);
398
399    pdc_begin_dict(p->out); 		/* XObject */
400
401    pdc_puts(p->out, "/Subtype/Image\n");
402
403    pdc_printf(p->out, "/Width %d\n", (int) image->width);
404    pdc_printf(p->out, "/Height %d\n", (int) fabs(image->height));
405
406    /*
407     * Transparency handling
408     */
409
410    /* Masking by color: single transparent color value */
411    if (image->transparent) {
412	pdf_colorspace *cs = &p->colorspaces[image->colorspace];
413
414	switch (cs->type) {
415	    case Indexed:
416	    case DeviceGray:
417	    pdc_printf(p->out,"/Mask[%d %d]\n",
418		(int) image->transval[0], (int) image->transval[0]);
419	    break;
420
421
422	    case DeviceRGB:
423	    pdc_printf(p->out,"/Mask[%d %d %d %d %d %d]\n",
424		(int) image->transval[0], (int) image->transval[0],
425		(int) image->transval[1], (int) image->transval[1],
426		(int) image->transval[2], (int) image->transval[2]);
427	    break;
428
429	    case DeviceCMYK:
430	    pdc_printf(p->out,"/Mask[%d %d %d %d %d %d %d %d]\n",
431		(int) image->transval[0], (int) image->transval[0],
432		(int) image->transval[1], (int) image->transval[1],
433		(int) image->transval[2], (int) image->transval[2],
434		(int) image->transval[3], (int) image->transval[3]);
435	    break;
436
437	    default:
438	    pdc_error(p->pdc, PDF_E_INT_BADCS,
439		pdc_errprintf(p->pdc, "%d",
440		    (int) p->colorspaces[image->colorspace].type), 0, 0, 0);
441	}
442
443    /* Masking by position: separate bitmap mask */
444    } else if (image->mask != pdc_undef && p->images[image->mask].bpc > 1) {
445        pdc_printf(p->out, "/SMask %ld 0 R\n",
446            p->xobjects[p->images[image->mask].no].obj_id);
447
448    } else if (image->mask != pdc_undef) {
449        pdc_printf(p->out, "/Mask %ld 0 R\n",
450            p->xobjects[p->images[image->mask].no].obj_id);
451    }
452
453    /*
454     * /BitsPerComponent is optional for image masks according to the
455     * PDF reference, but some viewers require it nevertheless.
456     * We must therefore always write it.
457     */
458    pdc_printf(p->out, "/BitsPerComponent %d\n", image->bpc);
459
460    if (image->imagemask) {
461	pdc_puts(p->out, "/ImageMask true\n");
462
463    } else {
464
465	switch (p->colorspaces[image->colorspace].type) {
466	    case DeviceGray:
467		break;
468
469	    case DeviceRGB:
470		break;
471
472	    case DeviceCMYK:
473		break;
474
475	    case Indexed:
476		break;
477
478
479
480	    default:
481		pdc_error(p->pdc, PDF_E_INT_BADCS,
482		    pdc_errprintf(p->pdc, "%d", image->colorspace), 0, 0, 0);
483        }
484
485        pdc_puts(p->out, "/ColorSpace");
486        pdf_write_colorspace(p, image->colorspace, pdc_false);
487        pdc_puts(p->out, "\n");
488    }
489
490    if (image->invert) {
491        pdc_puts(p->out, "/Decode[1 0");
492        for (i = 1; i < image->components; i++)
493            pdc_puts(p->out, " 1 0");
494        pdc_puts(p->out, "]\n");
495    }
496
497    if (image->ri != AutoIntent) {
498        pdc_printf(p->out, "/Intent/%s\n",
499            pdc_get_keyword(image->ri, gs_renderingintents));
500    }
501
502    if (image->interpolate) {
503        pdc_puts(p->out, "/Interpolate true\n");
504    }
505
506    /* special case: referenced image data instead of direct data */
507    if (image->reference != pdf_ref_direct) {
508
509	if (image->compression != none) {
510	    pdc_printf(p->out, "/FFilter[/%s]\n",
511		    pdf_filter_names[image->compression]);
512	}
513
514	if (image->compression == ccitt) {
515	    pdc_puts(p->out, "/FDecodeParms[<<");
516
517	    if ((int) image->width != 1728)	/* CCITT default width */
518		pdc_printf(p->out, "/Columns %d", (int) image->width);
519
520	    pdc_printf(p->out, "/Rows %d", (int) fabs(image->height));
521
522            if (image->K != 0)
523                pdc_printf(p->out, "/K %d", image->K);
524
525	    pdc_puts(p->out, ">>]\n");
526
527	}
528
529	if (image->reference == pdf_ref_file) {
530
531	    /* LATER: make image file name platform-neutral:
532	     * Change : to / on the Mac
533	     * Change \ to / on Windows
534	     */
535	    pdc_puts(p->out, "/F");
536	    pdc_put_pdfstring(p->out, image->filename,
537		(int) strlen(image->filename));
538            pdc_puts(p->out, "/Length 0");
539
540	} else if (image->reference == pdf_ref_url) {
541
542	    pdc_puts(p->out, "/F<</FS/URL/F");
543	    pdc_put_pdfstring(p->out, image->filename,
544		(int) strlen(image->filename));
545	    pdc_puts(p->out, ">>/Length 0");
546	}
547
548	pdc_end_dict(p->out);		/* XObject */
549
550	/* We must avoid pdc_begin/end_pdfstream() here in order to
551	 * generate a really empty stream.
552	 */
553	pdc_puts(p->out, "stream\n");	/* dummy image stream */
554	pdc_puts(p->out, "endstream\n");
555
556        pdc_end_obj(p->out);                    /* XObject */
557
558	if (PDF_GET_STATE(p) == pdf_state_page)
559	    pdf_begin_contents_section(p);
560
561	return;
562    }
563
564    /*
565     * Now the (more common) handling of actual image
566     * data to be included in the PDF output.
567     */
568    /* do we need a filter (either ASCII or decompression)? */
569
570    if (p->debug['a']) {
571	pdc_puts(p->out, "/Filter[/ASCIIHexDecode");
572	if (image->compression != none)
573	    pdc_printf(p->out, "/%s", pdf_filter_names[image->compression]);
574	pdc_puts(p->out, "]\n");
575
576    } else {
577	/* force compression if not a recognized precompressed image format */
578	if (!image->use_raw && pdc_get_compresslevel(p->out))
579	    image->compression = flate;
580
581	if (image->compression != none)
582	    pdc_printf(p->out, "/Filter/%s\n",
583		    pdf_filter_names[image->compression]);
584    }
585
586    /* prepare precompressed (raw) image data; avoid empty DecodeParms */
587    if (image->use_raw &&
588        (image->params ||
589	 image->predictor != pred_default ||
590	 image->compression == ccitt)) {
591
592	if (p->debug['a'])
593	    pdc_printf(p->out, "/DecodeParms[%s<<", "null");
594	else
595	    pdc_printf(p->out, "/DecodeParms<<");
596
597        /* write EarlyChange */
598        if (image->params)
599            pdc_puts(p->out, image->params);
600
601        if (image->compression == ccitt) {
602            if (image->K != 0)
603                pdc_printf(p->out, "/K %d", image->K);
604        }
605
606	if (image->compression == flate || image->compression == lzw) {
607	    if (image->predictor != pred_default) {
608		pdc_printf(p->out, "/Predictor %d", (int) image->predictor);
609		pdc_printf(p->out, "/Columns %d", (int) image->width);
610		if (image->bpc != 8)
611		    pdc_printf(p->out, "/BitsPerComponent %d", image->bpc);
612
613		if (image->components != 1)	/* 1 is default */
614		    pdc_printf(p->out, "/Colors %d", image->components);
615	    }
616	}
617
618	if (image->compression == ccitt) {
619	    if ((int) image->width != 1728)	/* CCITT default width */
620		pdc_printf(p->out, "/Columns %d", (int) image->width);
621
622	    pdc_printf(p->out, "/Rows %d", (int) fabs(image->height));
623	}
624
625	if (p->debug['a'])
626	    pdc_puts(p->out, ">>]\n");		/* DecodeParms dict and array */
627	else
628	    pdc_puts(p->out, ">>\n");		/* DecodeParms dict */
629    }
630
631    /* Write the actual image data */
632    length_id = pdc_alloc_id(p->out);
633
634    pdc_printf(p->out,"/Length %ld 0 R\n", length_id);
635    pdc_end_dict(p->out);		/* XObject */
636
637    /* image data */
638
639    if (p->debug['a'])
640	pdf_ASCIIHexEncode(p, &image->src);
641    else {
642	pdf_copy_stream(p, &image->src, !image->use_raw);	/* image data */
643    }
644
645    pdc_end_obj(p->out);	/* XObject */
646
647    pdc_put_pdfstreamlength(p->out, length_id);
648
649    if (p->flush & pdf_flush_content)
650	pdc_flush_stream(p->out);
651
652    /*
653     * Write colormap information for indexed color spaces
654     */
655    if (firststrip && p->colorspaces[image->colorspace].type == Indexed) {
656	pdf_write_colormap(p, image->colorspace);
657    }
658
659    if (PDF_GET_STATE(p) == pdf_state_page)
660	pdf_begin_contents_section(p);
661
662    if (p->flush & pdf_flush_content)
663	pdc_flush_stream(p->out);
664}
665
666void
667pdf__fit_image(PDF *p, int im, float x, float y, const char *optlist)
668{
669    pdf_image *image;
670    int legal_states;
671
672    pdf_check_handle(p, im, pdc_imagehandle);
673
674    image = &p->images[im];
675
676    if (PDF_GET_STATE(p) == pdf_state_glyph && !pdf_get_t3colorized(p) &&
677        image->imagemask == pdc_false)
678        legal_states = pdf_state_page | pdf_state_pattern | pdf_state_template;
679    else
680        legal_states = pdf_state_content;
681    PDF_CHECK_STATE(p, legal_states);
682
683    if (PDF_GET_STATE(p) == pdf_state_template && im == p->templ)
684        pdc_error(p->pdc, PDF_E_TEMPLATE_SELF,
685            pdc_errprintf(p->pdc, "%d", im), 0, 0, 0);
686
687    pdf_place_xobject(p, im, x, y, optlist);
688}
689
690PDFLIB_API void PDFLIB_CALL
691PDF_fit_image(PDF *p, int image, float x, float y, const char *optlist)
692{
693    static const char fn[] = "PDF_fit_image";
694
695    /* precise scope diagnosis in pdf__fit_image */
696    if (pdf_enter_api(p, fn, pdf_state_all,
697        "(p[%p], %d, %g, %g, \"%s\")\n", (void *) p, image, x, y, optlist))
698    {
699        PDF_INPUT_HANDLE(p, image)
700        pdf__fit_image(p, image, x, y, optlist);
701    }
702}
703
704PDFLIB_API void PDFLIB_CALL
705PDF_place_image(PDF *p, int image, float x, float y, float scale)
706{
707    static const char fn[] = "PDF_place_image";
708
709    /* precise scope diagnosis in pdf__fit_image */
710    if (pdf_enter_api(p, fn, pdf_state_all,
711        "(p[%p], %d, %g, %g, %g)\n", (void *) p, image, x, y, scale))
712    {
713        char optlist[32];
714        sprintf(optlist, "dpi none  scale %g", scale);
715        PDF_INPUT_HANDLE(p, image)
716        pdf__fit_image(p, image, x, y, optlist);
717    }
718}
719
720/* definitions of place image options */
721static const pdc_defopt pdf_place_xobject_options[] =
722{
723    {"dpi", pdc_floatlist, 0, 1, 2, 0.0, INT_MAX, pdf_dpi_keylist},
724
725    {"scale", pdc_floatlist, PDC_OPT_NOZERO, 1, 2, PDC_FLOAT_MIN, PDC_FLOAT_MAX,
726     NULL},
727
728    {"orientate", pdc_keywordlist, 0, 1, 1, 0.0, 0.0, pdf_orientate_keylist},
729
730    {"boxsize", pdc_floatlist, 0, 2, 2, PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},
731
732    {"rotate", pdc_floatlist, 0, 1, 1, PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},
733
734    {"position", pdc_floatlist, 0, 1, 2, PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},
735
736    {"fitmethod", pdc_keywordlist, 0, 1, 1, 0.0, 0.0, pdf_fitmethod_keylist},
737
738    {"distortionlimit", pdc_floatlist, PDC_OPT_NONE, 1, 1, 0.0, 100.0, NULL},
739
740    {"adjustpage", pdc_booleanlist, PDC_OPT_PDC_1_3, 1, 1, 0.0, 0.0, NULL},
741
742    {"blind", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
743
744    PDC_OPT_TERMINATE
745};
746
747void
748pdf_place_xobject(PDF *p, int im, float x, float y, const char *optlist)
749{
750    pdf_image *image;
751    pdc_resopt *results;
752    pdc_clientdata data;
753    pdc_matrix m;
754    pdc_fitmethod method;
755    pdc_vector imgscale, elemsize, elemscale, relpos, polyline[5];
756    pdc_box fitbox, elembox;
757    pdc_scalar ss, scaley, rowsize = 1, lastratio = 1, minfscale;
758    pdc_bool adjustpage, hasresol;
759    pdc_bool blindmode;
760    pdc_bool negdir = pdc_false;
761    float dpi[2], scale[2], boxsize[2], position[2], angle, distortionlimit;
762    float dpi_x, dpi_y, tx = 0, ty = 0;
763    int orientangle, indangle;
764    int inum, num, is, ip, islast;
765    int imageno;
766
767    image = &p->images[im];
768
769    /* has resolution (image_xobject) */
770    hasresol = p->xobjects[image->no].type == image_xobject ?
771                   pdc_true : pdc_false;
772
773    /* defaults */
774    orientangle = 0;
775    dpi[0] = dpi[1] = (float) 0.0;
776    scale[0] = scale[1] = (float) 1.0;
777    boxsize[0] = boxsize[1] = (float) 0.0;
778    position[0] = position[1] = (float) 0.0;
779    angle = (float) 0.0;
780    method = pdc_nofit;
781    distortionlimit = (float) 75.0;
782    adjustpage = pdc_false;
783    blindmode = pdc_false;
784
785    /* parsing optlist */
786    if (optlist && strlen(optlist))
787    {
788        data.compatibility = p->compatibility;
789        results = pdc_parse_optionlist(p->pdc, optlist,
790                                       pdf_place_xobject_options,
791                                       &data, pdc_true);
792
793        /* save and check options */
794        if (hasresol)
795            dpi[0] = (float) dpi_internal;
796        if ((num = pdc_get_optvalues(p->pdc, "dpi", results, dpi, NULL)) > 0)
797        {
798            if (!hasresol && dpi[0] != (float) dpi_none)
799                pdc_warning(p->pdc, PDC_E_OPT_IGNORED, "dpi", 0, 0, 0);
800            else if (num == 1)
801                dpi[1] = dpi[0];
802        }
803
804        if (1 == pdc_get_optvalues(p->pdc, "scale", results, scale, NULL))
805            scale[1] = scale[0];
806
807        pdc_get_optvalues(p->pdc, "orientate", results, &orientangle, NULL);
808
809        pdc_get_optvalues(p->pdc, "boxsize", results, boxsize, NULL);
810
811        pdc_get_optvalues(p->pdc, "rotate", results, &angle, NULL);
812
813        if (1 == pdc_get_optvalues(p->pdc, "position", results, position, NULL))
814            position[1] = position[0];
815
816        if (pdc_get_optvalues(p->pdc, "fitmethod", results, &inum, NULL))
817            method = (pdc_fitmethod) inum;
818
819        pdc_get_optvalues(p->pdc, "distortionlimit", results,
820                          &distortionlimit, NULL);
821
822        pdc_get_optvalues(p->pdc, "adjustpage", results, &adjustpage, NULL);
823        pdc_get_optvalues(p->pdc, "blind", results, &blindmode, NULL);
824
825        pdc_cleanup_optionlist(p->pdc, results);
826    }
827
828    /* calculation of image scale and size */
829    imgscale.x = scale[0];
830    imgscale.y = scale[1];
831    if (hasresol)
832    {
833        if (dpi[0] == (float) dpi_internal)
834        {
835            dpi_x = image->dpi_x;
836            dpi_y = image->dpi_y;
837            if (dpi_x > 0 && dpi_y > 0)
838            {
839                imgscale.x *= 72.0 / dpi_x;
840                imgscale.y *= 72.0 / dpi_y;
841            }
842            else if (dpi_x < 0 && dpi_y < 0)
843            {
844                imgscale.y *= dpi_y / dpi_x;
845            }
846        }
847        else if (dpi[0] > 0)
848        {
849            imgscale.x *= 72.0 / dpi[0];
850            imgscale.y *= 72.0 / dpi[1];
851        }
852        rowsize = imgscale.y * image->rowsperstrip;
853        imgscale.x *= image->width;
854        imgscale.y *= image->height;
855        lastratio = (imgscale.y / rowsize) - (image->strips - 1);
856        elemsize.x = imgscale.x;
857        elemsize.y = imgscale.y;
858    }
859    else
860    {
861        elemsize.x = imgscale.x * image->width;
862        elemsize.y = imgscale.y * image->height;
863    }
864
865    /* negative direction (e.g. BMP images) */
866    if (image->height < 0)
867    {
868        elemsize.y = -elemsize.y;
869        negdir = pdc_true;
870    }
871
872    /* minimal horizontal scaling factor */
873    minfscale = distortionlimit / 100.0;
874
875    /* orientation */
876    indangle = orientangle / 90;
877    if (indangle % 2)
878    {
879        ss = elemsize.x;
880        elemsize.x = elemsize.y;
881        elemsize.y = ss;
882    }
883
884    /* box for fitting */
885    fitbox.ll.x = 0;
886    fitbox.ll.y = 0;
887    fitbox.ur.x = boxsize[0];
888    fitbox.ur.y = boxsize[1];
889
890    /* relative position */
891    relpos.x = position[0] / 100.0;
892    relpos.y = position[1] / 100.0;
893
894    /* calculate image box */
895    pdc_place_element(method, minfscale, &fitbox, &relpos,
896                      &elemsize, &elembox, &elemscale);
897
898    /* adjust page size */
899    if (adjustpage && PDF_GET_STATE(p) == pdf_state_page)
900    {
901	float urx, ury, height;
902
903	urx = (float) (2 * x + elembox.ur.x);
904	ury = (float) (2 * y + elembox.ur.y);
905	pdc_transform_point(&p->gstate[p->sl].ctm,
906			    urx, ury, &p->width, &height);
907	p->height = (p->ydirection > 0) ?
908			height : p->height - p->ydirection * height;
909	if (p->height < p->ydirection * height / 2.0)
910	    pdc_error(p->pdc, PDF_E_IMAGE_NOADJUST, 0, 0, 0, 0);
911
912	p->CropBox.llx = 0.0f;
913	p->CropBox.lly = 0.0f;
914	p->CropBox.urx = p->width;
915	p->CropBox.ury = p->height;
916
917	if ((p->width < PDF_ACRO4_MINPAGE || p->width > PDF_ACRO4_MAXPAGE ||
918	     p->height < PDF_ACRO4_MINPAGE || p->height > PDF_ACRO4_MAXPAGE))
919		pdc_warning(p->pdc, PDF_E_PAGE_SIZE_ACRO4, 0, 0, 0, 0);
920    }
921
922    if (!blindmode)
923    {
924        pdf_end_text(p);
925        pdf_begin_contents_section(p);
926
927        pdf__save(p);
928    }
929
930    /* reference point */
931    pdc_translation_matrix(x, y, &m);
932    pdf_concat_raw_ob(p, &m, blindmode);
933
934    /* clipping */
935    if (!blindmode && (method == pdc_clip || method == pdc_slice))
936    {
937        pdf__rect(p, 0, 0, boxsize[0], boxsize[1]);
938        pdf__clip(p);
939    }
940
941    /* optional rotation */
942    if (fabs((double)(angle)) > PDC_FLOAT_PREC)
943    {
944        pdc_rotation_matrix(p->ydirection * angle, &m);
945        pdf_concat_raw_ob(p, &m, blindmode);
946    }
947
948    /* translation of element box */
949    elembox.ll.y *= p->ydirection;
950    elembox.ur.y *= p->ydirection;
951    pdc_box2polyline(&elembox, polyline);
952    ip = indangle;
953    if (negdir)
954    {
955        ip = indangle - 1;
956        if (ip < 0) ip = 3;
957    }
958    tx = (float) polyline[ip].x;
959    ty = (float) polyline[ip].y;
960    pdc_translation_matrix(tx, ty, &m);
961    pdf_concat_raw_ob(p, &m, blindmode);
962
963    /* orientation of image */
964    if (orientangle != 0)
965    {
966        pdc_rotation_matrix(p->ydirection * orientangle, &m);
967        pdf_concat_raw_ob(p, &m, blindmode);
968        if (indangle % 2)
969        {
970            ss = elemscale.x;
971            elemscale.x = elemscale.y;
972            elemscale.y = ss;
973        }
974    }
975
976    /* scaling of image */
977    if (image->strips == 1)
978        scaley = p->ydirection * imgscale.y * elemscale.y;
979    else
980        scaley = p->ydirection * rowsize * elemscale.y;
981    pdc_scale_matrix((float)(imgscale.x * elemscale.x), (float) scaley, &m);
982    pdf_concat_raw_ob(p, &m, blindmode);
983
984    if (!hasresol && !blindmode)
985    {
986        pdf_reset_gstate(p);
987        pdf_reset_tstate(p);
988    }
989
990
991    if (!blindmode)
992    {
993        /* last strip first */
994        if (image->strips > 1 && lastratio != 1.0)
995        {
996	    pdc_scale_matrix((float) 1.0, (float) lastratio, &m);
997	    pdf_concat_raw(p, &m);
998	}
999
1000        /* put out image strips separately if available */
1001        islast = image->strips - 1;
1002        imageno = image->no + islast;
1003        for (is = islast; is >= 0; is--)
1004        {
1005            pdc_printf(p->out, "/I%d Do\n", imageno);
1006            p->xobjects[imageno].flags |= xobj_flag_write;
1007            if (image->strips > 1 && is > 0)
1008            {
1009                pdc_translation_matrix(0, 1, &m);
1010                pdf_concat_raw(p, &m);
1011                if (is == islast && lastratio != 1.0)
1012		{
1013		    pdc_scale_matrix((float) 1.0, (float) (1. / lastratio), &m);
1014		    pdf_concat_raw(p, &m);
1015		}
1016                imageno--;
1017            }
1018        }
1019        if (image->mask != pdc_undef)
1020            p->xobjects[p->images[image->mask].no].flags |= xobj_flag_write;
1021
1022        pdf__restore(p);
1023    }
1024}
1025
1026#define MAX_THUMBNAIL_SIZE	106
1027
1028PDFLIB_API void PDFLIB_CALL
1029PDF_add_thumbnail(PDF *p, int im)
1030{
1031    static const char fn[] = "PDF_add_thumbnail";
1032    pdf_image *image;
1033
1034    if (!pdf_enter_api(p, fn, pdf_state_page, "(p[%p], %d)\n", (void *) p, im))
1035	return;
1036
1037    PDF_INPUT_HANDLE(p, im)
1038    pdf_check_handle(p, im, pdc_imagehandle);
1039
1040    if (p->thumb_id != PDC_BAD_ID)
1041	pdc_error(p->pdc, PDF_E_IMAGE_THUMB, 0, 0, 0, 0);
1042
1043    image = &p->images[im];
1044
1045    if (image->strips > 1)
1046	pdc_error(p->pdc, PDF_E_IMAGE_THUMB_MULTISTRIP,
1047	    pdc_errprintf(p->pdc, "%d", im), 0, 0, 0);
1048
1049    if (image->width > MAX_THUMBNAIL_SIZE || image->height > MAX_THUMBNAIL_SIZE)
1050	pdc_error(p->pdc, PDF_E_IMAGE_THUMB_SIZE,
1051	    pdc_errprintf(p->pdc, "%d", im),
1052	    pdc_errprintf(p->pdc, "%d", MAX_THUMBNAIL_SIZE), 0, 0);
1053
1054    if (image->colorspace != (int) DeviceGray &&
1055        image->colorspace != (int) DeviceRGB &&
1056        image->colorspace != (int) Indexed)
1057	pdc_error(p->pdc, PDF_E_IMAGE_THUMB_CS,
1058	    pdc_errprintf(p->pdc, "%d", im), 0, 0, 0);
1059
1060    /* Add the image to the thumbnail key of the current page.  */
1061    p->thumb_id = p->xobjects[image->no].obj_id;
1062}
1063
1064PDFLIB_API void PDFLIB_CALL
1065PDF_close_image(PDF *p, int image)
1066{
1067    static const char fn[] = "PDF_close_image";
1068
1069    if (!pdf_enter_api(p, fn,
1070        (pdf_state) (pdf_state_document | pdf_state_page | pdf_state_font),
1071	"(p[%p], %d)\n", (void *) p, image))
1072    {
1073	return;
1074    }
1075
1076    PDF_INPUT_HANDLE(p, image)
1077    pdf_check_handle(p, image, pdc_imagehandle);
1078
1079    pdf_cleanup_image(p, image);
1080}
1081
1082/* interface for using image data directly in memory */
1083
1084PDFLIB_API int PDFLIB_CALL
1085PDF_open_image(
1086    PDF *p,
1087    const char *type,
1088    const char *source,
1089    const char *data,
1090    long length,
1091    int width,
1092    int height,
1093    int components,
1094    int bpc,
1095    const char *params)
1096{
1097    static const char fn[] = "PDF_open_image";
1098    const char *filename = data;
1099    char optlist[512];
1100    pdc_bool memory = pdc_false;
1101    int retval = -1;
1102
1103    /* precise scope diagnosis in pdf__load_image */
1104    if (!pdf_enter_api(p, fn, pdf_state_all,
1105	"(p[%p], \"%s\", \"%s\", data[%p], %ld, %d, %d, %d, %d, \"%s\")",
1106    	(void *) p, type, source, (void *) data, length,
1107	width, height, components, bpc, params))
1108    {
1109        PDF_RETURN_HANDLE(p, retval)
1110    }
1111
1112    if (type == NULL || *type == '\0')
1113	pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "type", 0, 0, 0);
1114
1115    if (source == NULL || *source == '\0')
1116	pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "source", 0, 0, 0);
1117
1118    if (!strcmp(type, "raw") && data == NULL)
1119	pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "data", 0, 0, 0);
1120
1121    /* create optlist */
1122    optlist[0] = 0;
1123    sprintf(optlist,"width %d  height %d  components %d  bpc %d ",
1124            width, height, components, bpc);
1125
1126    if (length < 0L)
1127    {
1128        strcat(optlist, "bitreverse true ");
1129        length = -length;
1130    }
1131
1132    strcat(optlist, "reftype ");
1133    if (!strcmp(source, "fileref"))
1134        strcat(optlist, "fileref ");
1135    else if (!strcmp(source, "memory"))
1136    {
1137        memory = pdc_true;
1138        strcat(optlist, "direct ");
1139    }
1140    else if (!strcmp(source, "url"))
1141        strcat(optlist, "url ");
1142
1143    if (params != NULL && *params != '\0')
1144    {
1145        char **items;
1146        int i, nitems;
1147
1148        /* separator characters because of compatibility */
1149        nitems = pdc_split_stringlist(p->pdc, params, "\t :", &items);
1150        for (i = 0; i < nitems; i++)
1151        {
1152            if (!strcmp(items[i], "invert"))
1153                strcat(optlist, "invert true ");
1154            else if (!strcmp(items[i], "ignoremask"))
1155                strcat(optlist, "ignoremask true ");
1156            else if (!strcmp(items[i], "inline"))
1157                strcat(optlist, "inline true ");
1158            else if (!strcmp(items[i], "interpolate"))
1159                strcat(optlist, "interpolate true ");
1160            else if (!strcmp(items[i], "mask"))
1161                strcat(optlist, "mask true ");
1162            else if (!strcmp(items[i], "/K"))
1163                strcat(optlist, "K ");
1164            else if (!strcmp(items[i], "/BlackIs1"))
1165                strcat(optlist, "invert ");
1166            else
1167                strcat(optlist, items[i]);
1168        }
1169        pdc_cleanup_stringlist(p->pdc, items);
1170    }
1171
1172    /* create virtual file */
1173    if (memory)
1174    {
1175        filename = "__raw__image__data__";
1176        pdf__create_pvf(p, filename, 0, data, (size_t) length, "");
1177    }
1178
1179    retval = pdf__load_image(p, type, filename, (const char *) optlist);
1180
1181    if (memory)
1182        (void) pdf__delete_pvf(p, filename, 0);
1183
1184    PDF_RETURN_HANDLE(p, retval)
1185}
1186
1187PDFLIB_API int PDFLIB_CALL
1188PDF_open_image_file(
1189    PDF *p,
1190    const char *type,
1191    const char *filename,
1192    const char *stringparam,
1193    int intparam)
1194{
1195    static const char fn[] = "PDF_open_image_file";
1196    char optlist[256];
1197    int retval = -1;
1198
1199    /* precise scope diagnosis in pdf__load_image */
1200    if (!pdf_enter_api(p, fn, pdf_state_all,
1201	"(p[%p], \"%s\", \"%s\", \"%s\", %d)",
1202	(void *) p, type, filename, stringparam, intparam))
1203    {
1204        PDF_RETURN_HANDLE(p, retval)
1205    }
1206
1207    optlist[0] = 0;
1208    if (stringparam != NULL && *stringparam != '\0')
1209    {
1210        if (!strcmp(stringparam, "invert"))
1211            strcpy(optlist, "invert true ");
1212        else if (!strcmp(stringparam, "inline"))
1213            strcpy(optlist, "inline true ");
1214        else if (!strcmp(stringparam, "ignoremask"))
1215            strcpy(optlist, "ignoremask true ");
1216        else if (!strcmp(stringparam, "mask"))
1217            strcpy(optlist, "mask true ");
1218        else if (!strcmp(stringparam, "masked"))
1219            sprintf(optlist, "masked %d ", intparam);
1220        else if (!strcmp(stringparam, "colorize"))
1221            sprintf(optlist, "colorize %d ", intparam);
1222        else if (!strcmp(stringparam, "page"))
1223            sprintf(optlist, "page %d ", intparam);
1224        else if (!strcmp(stringparam, "iccprofile"))
1225            sprintf(optlist, "iccprofile %d ", intparam);
1226    }
1227
1228    retval = pdf__load_image(p, type, filename, (const char *) optlist);
1229
1230    PDF_RETURN_HANDLE(p, retval)
1231}
1232
1233PDFLIB_API int PDFLIB_CALL
1234PDF_open_CCITT(PDF *p, const char *filename, int width, int height,
1235               int BitReverse, int K, int BlackIs1)
1236{
1237    static const char fn[] = "PDF_open_CCITT";
1238    int retval = -1;
1239
1240    if (pdf_enter_api(p, fn,
1241        (pdf_state) (pdf_state_document | pdf_state_page | pdf_state_font),
1242        "(p[%p], \"%s\", %d, %d, %d, %d, %d)",
1243        (void *) p, filename, width, height, BitReverse, K, BlackIs1))
1244    {
1245        /* create optlist */
1246        char optlist[256];
1247        sprintf(optlist,"width %d  height %d  bitreverse %s  K %d  invert %s",
1248            width, height, PDC_BOOLSTR(BitReverse), K, PDC_BOOLSTR(BlackIs1));
1249
1250        retval = pdf__load_image(p, "CCITT", filename, (const char *) optlist);
1251    }
1252
1253    PDF_RETURN_HANDLE(p, retval)
1254}
1255
1256PDFLIB_API int PDFLIB_CALL
1257PDF_load_image(
1258    PDF *p,
1259    const char *type,
1260    const char *filename,
1261    int reserved,
1262    const char *optlist)
1263{
1264    static const char fn[] = "PDF_load_image";
1265    int retval = -1;
1266
1267    /* precise scope diagnosis in pdf__load_image */
1268    if (pdf_enter_api(p, fn, pdf_state_all,
1269        "(p[%p], \"%s\", \"%s\", %d ,\"%s\")",
1270        (void *) p, type, filename, reserved, optlist))
1271    {
1272        retval = pdf__load_image(p, type, filename, optlist);
1273    }
1274
1275    PDF_RETURN_HANDLE(p, retval)
1276}
1277
1278
1279/* keywords for options 'reftype' */
1280static const pdc_keyconn pdf_reftype_keys[] =
1281{
1282    {"direct",  pdf_ref_direct},
1283    {"fileref", pdf_ref_file},
1284    {"url",     pdf_ref_url},
1285    {NULL, 0}
1286};
1287
1288/* allowed values for options 'bcp' */
1289static const pdc_keyconn pdf_bpcvalues[] =
1290{
1291    {"1", 1}, {"2", 2}, {"4", 4}, {"8", 8}, {NULL, 0}
1292};
1293
1294/* allowed values for options 'components' */
1295static const pdc_keyconn pdf_compvalues[] =
1296{
1297    {"1", 1}, {"3", 3}, {"4", 4}, {NULL, 0}
1298};
1299
1300#define PDF_ICCOPT_FLAG PDC_OPT_UNSUPP
1301
1302/* definitions of open image options */
1303static const pdc_defopt pdf_open_image_options[] =
1304{
1305    {"bitreverse", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
1306
1307    {"bpc", pdc_integerlist, PDC_OPT_INTLIST, 1, 1, 1.0, 8.0, pdf_bpcvalues},
1308
1309    {"components", pdc_integerlist, PDC_OPT_INTLIST, 1, 1, 1.0, 4.0,
1310      pdf_compvalues},
1311
1312    {"height", pdc_integerlist, 0, 1, 1, 1.0, INT_MAX,  NULL},
1313
1314    {"honoriccprofile", pdc_booleanlist, PDF_ICCOPT_FLAG, 1, 1, 0.0, 0.0, NULL},
1315
1316    /* ordering of the next three options is significant */
1317
1318    {"iccprofile", pdc_iccprofilehandle, PDF_ICCOPT_FLAG, 1, 1, 1.0, 0.0, NULL},
1319
1320    {"colorize", pdc_colorhandle, PDC_OPT_IGNOREIF1, 1, 1, 0.0, 0.0, NULL},
1321
1322    {"mask", pdc_booleanlist, PDC_OPT_IGNOREIF2, 1, 1, 0.0, 0.0, NULL},
1323
1324    {"ignoremask", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
1325
1326    {"imagewarning", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
1327
1328    {"inline", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
1329
1330    {"interpolate", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
1331
1332    {"invert", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
1333
1334    {"K", pdc_integerlist, 0, 1, 1, -1.0, 1.0, NULL},
1335
1336    {"masked", pdc_imagehandle, 0, 1, 1, 0.0, 0.0, NULL},
1337
1338    {"page", pdc_integerlist, 0, 1, 1, 1.0, INT_MAX, NULL},
1339
1340    {"renderingintent", pdc_keywordlist, 0, 1, 1, 0.0, 0.0,
1341      gs_renderingintents},
1342
1343    {"reftype", pdc_keywordlist, 0, 1, 1, 0.0, 0.0, pdf_reftype_keys},
1344
1345    {"width", pdc_integerlist, 0, 1, 1, 1.0, INT_MAX, NULL},
1346
1347    PDC_OPT_TERMINATE
1348};
1349
1350int
1351pdf__load_image(
1352    PDF *p,
1353    const char *type,
1354    const char *filename,
1355    const char *optlist)
1356{
1357    const char *keyword = NULL;
1358    char qualname[32];
1359    pdc_clientdata data;
1360    pdc_resopt *results;
1361    pdf_image_type imgtype;
1362    int colorize = pdc_undef;
1363    pdf_image *image;
1364    pdc_bool indjpeg = pdc_false;
1365    int legal_states = 0;
1366    int k, inum, imageslot, retval = -1;
1367
1368    if (type == NULL || *type == '\0')
1369        pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "type", 0, 0, 0);
1370
1371    if (filename == NULL || *filename == '\0')
1372        pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "filename", 0, 0, 0);
1373
1374    /* parsing image type */
1375    k = pdc_get_keycode_ci(type, pdf_image_keylist);
1376    if (k == PDC_KEY_NOTFOUND)
1377        pdc_error(p->pdc, PDC_E_ILLARG_STRING, "type", type, 0, 0);
1378    imgtype = (pdf_image_type) k;
1379    type = pdc_get_keyword(imgtype, pdf_image_keylist);
1380
1381    /* automatic check */
1382    if (imgtype == pdf_img_auto)
1383    {
1384        pdc_file *fp;
1385        pdf_jpeg_info jpeg_info;
1386        pdf_tiff_info tiff_info;
1387
1388        if ((fp = pdf_fopen(p, filename, "", PDC_FILE_BINARY)) == NULL)
1389	{
1390	    if (p->debug['i'])
1391		pdc_error(p->pdc, -1, 0, 0, 0, 0);
1392
1393            return -1;
1394	}
1395
1396        if (pdf_is_BMP_file(p, fp))
1397            imgtype = pdf_img_bmp;
1398        else if (pdf_is_GIF_file(p, fp))
1399            imgtype = pdf_img_gif;
1400        else if (pdf_is_PNG_file(p, fp))
1401            imgtype = pdf_img_png;
1402        else if (pdf_is_TIFF_file(p, fp, &tiff_info, pdc_true))
1403            imgtype = pdf_img_tiff;
1404        else if (pdf_is_JPEG_file(p, fp, &jpeg_info))
1405            imgtype = pdf_img_jpeg;
1406        else
1407        {
1408            pdc_fclose(fp);
1409
1410	    pdc_set_errmsg(p->pdc, PDF_E_IMAGE_UNKNOWN, filename, 0, 0, 0);
1411
1412            if (p->debug['i'])
1413                pdc_error(p->pdc, -1, 0, 0, 0, 0);
1414
1415            return -1;
1416        }
1417        pdc_fclose(fp);
1418        type = pdc_get_keyword(imgtype, pdf_image_keylist);
1419    }
1420
1421    /* find free slot */
1422    for (imageslot = 0; imageslot < p->images_capacity; imageslot++)
1423        if (!p->images[imageslot].in_use)
1424            break;
1425
1426    if (imageslot == p->images_capacity)
1427        pdf_grow_images(p);
1428    image = &p->images[imageslot];
1429
1430    /* inherit global flags */
1431    image->verbose = p->debug['i'];
1432    image->ri = p->rendintent;
1433
1434    /* parsing optlist */
1435    if (optlist && strlen(optlist))
1436    {
1437        data.compatibility = p->compatibility;
1438        data.maxcolor = p->colorspaces_number - 1;
1439        data.maximage = p->images_capacity - 1;
1440        data.hastobepos = p->hastobepos;
1441        results = pdc_parse_optionlist(p->pdc, optlist, pdf_open_image_options,
1442                                       &data, image->verbose);
1443        if (!results)
1444            return -1;
1445
1446        /* save and check options */
1447        keyword = "imagewarning";
1448        pdc_get_optvalues(p->pdc, keyword, results,
1449                          &image->verbose, NULL);
1450        keyword = "reftype";
1451        if (pdc_get_optvalues(p->pdc, keyword, results, &inum, NULL))
1452        {
1453            image->reference = (pdf_ref_type) inum;
1454            if (image->reference != pdf_ref_direct &&
1455                imgtype != pdf_img_ccitt &&
1456                imgtype != pdf_img_jpeg &&
1457                imgtype != pdf_img_raw)
1458            {
1459                if (image->verbose)
1460                    pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword, type,
1461                                0, 0);
1462                image->reference = pdf_ref_direct;
1463            }
1464        }
1465        indjpeg = (imgtype == pdf_img_jpeg &&
1466                   image->reference != pdf_ref_direct) ? pdc_true : pdc_false;
1467
1468        keyword = "bpc";
1469        if (pdc_get_optvalues(p->pdc, keyword, results,
1470                              &image->bpc, NULL))
1471        {
1472            if (image->verbose && imgtype != pdf_img_raw && !indjpeg)
1473                pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, type, 0, 0);
1474        }
1475
1476        keyword = "components";
1477        if (pdc_get_optvalues(p->pdc, keyword, results,
1478                              &image->components, NULL))
1479        {
1480            if (image->verbose && imgtype != pdf_img_raw && !indjpeg)
1481                pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, type, 0, 0);
1482        }
1483
1484        keyword = "height";
1485        if (pdc_get_optvalues(p->pdc, keyword, results,
1486                              &image->height_pixel, NULL))
1487        {
1488            if (image->verbose && imgtype != pdf_img_ccitt &&
1489                                  imgtype != pdf_img_raw && !indjpeg)
1490                pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, type, 0, 0);
1491        }
1492
1493        keyword = "width";
1494        if (pdc_get_optvalues(p->pdc, keyword, results,
1495                              &image->width_pixel, NULL))
1496        {
1497            if (image->verbose && imgtype != pdf_img_raw &&
1498                                  imgtype != pdf_img_ccitt && !indjpeg)
1499                pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, type, 0, 0);
1500        }
1501
1502        keyword = "bitreverse";
1503        if (pdc_get_optvalues(p->pdc, keyword, results,
1504                              &image->bitreverse, NULL))
1505        {
1506            if (image->verbose && image->bitreverse &&
1507               (imgtype != pdf_img_ccitt || image->reference != pdf_ref_direct))
1508                pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, type, 0, 0);
1509        }
1510
1511        keyword = "colorize";
1512        pdc_get_optvalues(p->pdc, keyword, results, &colorize, NULL);
1513
1514
1515        keyword = "ignoremask";
1516        if (pdc_get_optvalues(p->pdc, keyword, results,
1517                              &image->ignoremask, NULL))
1518        {
1519            if (image->verbose && (imgtype == pdf_img_bmp ||
1520                                   imgtype == pdf_img_ccitt ||
1521                                   imgtype == pdf_img_raw))
1522                pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword, type, 0, 0);
1523        }
1524
1525        keyword = "inline";
1526        if (pdc_get_optvalues(p->pdc, keyword, results,
1527                              &image->doinline, NULL) && image->doinline)
1528        {
1529            if (imgtype != pdf_img_ccitt &&
1530                imgtype != pdf_img_jpeg &&
1531                imgtype != pdf_img_raw)
1532            {
1533                if (image->verbose)
1534                    pdc_warning(p->pdc,
1535                    PDF_E_IMAGE_OPTUNSUPP, keyword, type, 0, 0);
1536                image->doinline = pdc_false;
1537            }
1538            else if (image->verbose && image->reference != pdf_ref_direct)
1539            {
1540                pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, type, 0, 0);
1541                image->doinline = pdc_false;
1542            }
1543        }
1544
1545        keyword = "interpolate";
1546        pdc_get_optvalues(p->pdc, keyword, results,
1547                          &image->interpolate, NULL);
1548
1549        keyword = "invert";
1550        pdc_get_optvalues(p->pdc, keyword, results,
1551                              &image->invert, NULL);
1552
1553        keyword = "K";
1554        if (pdc_get_optvalues(p->pdc, keyword, results,
1555                              &image->K, NULL))
1556        {
1557            if (image->verbose && imgtype != pdf_img_ccitt)
1558                pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, type, 0, 0);
1559        }
1560
1561        keyword = "mask";
1562        pdc_get_optvalues(p->pdc, keyword, results,
1563                              &image->imagemask, NULL);
1564
1565        keyword = "masked";
1566        if (pdc_get_optvalues(p->pdc, keyword, results,
1567                              &image->mask, NULL))
1568        {
1569            if (!p->images[image->mask].in_use ||
1570                 p->images[image->mask].strips != 1 ||
1571                (p->compatibility <= PDC_1_3 &&
1572                (p->images[image->mask].imagemask != pdc_true ||
1573                 p->images[image->mask].bpc != 1)))
1574            {
1575                pdc_set_errmsg(p->pdc, PDF_E_IMAGE_OPTBADMASK, keyword,
1576                          pdc_errprintf(p->pdc, "%d", image->mask), 0, 0);
1577
1578                if (image->verbose)
1579                    pdc_error(p->pdc, -1, 0, 0, 0, 0);
1580
1581                pdc_cleanup_optionlist(p->pdc, results);
1582                pdf_cleanup_image(p, imageslot);
1583                return -1;
1584            }
1585        }
1586
1587        keyword = "renderingintent";
1588        if (pdc_get_optvalues(p->pdc, keyword, results, &inum, NULL))
1589            image->ri = (pdf_renderingintent) inum;
1590
1591        keyword = "page";
1592        if (pdc_get_optvalues(p->pdc, keyword, results,
1593                              &image->page, NULL))
1594        {
1595            if (imgtype != pdf_img_gif && imgtype != pdf_img_tiff)
1596            {
1597                if (image->page == 1)
1598                {
1599                    if (image->verbose)
1600                        pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword,
1601                                    type, 0, 0);
1602                }
1603                else
1604                {
1605                    pdc_set_errmsg(p->pdc, PDF_E_IMAGE_NOPAGE,
1606                              pdc_errprintf(p->pdc, "%d", image->page), type,
1607                              pdc_errprintf(p->pdc, "%s", filename), 0);
1608
1609                    if (image->verbose)
1610                        pdc_error(p->pdc, -1, 0, 0, 0, 0);
1611
1612                    pdc_cleanup_optionlist(p->pdc, results);
1613                    pdf_cleanup_image(p, imageslot);
1614                    return -1;
1615                }
1616            }
1617        }
1618
1619        pdc_cleanup_optionlist(p->pdc, results);
1620    }
1621
1622    /* precise scope diagnosis */
1623    if (image->doinline)
1624        legal_states = pdf_state_content;
1625    else
1626        legal_states = pdf_state_document | pdf_state_page | pdf_state_font;
1627    PDF_CHECK_STATE(p, legal_states);
1628
1629    /* required options */
1630    if (imgtype == pdf_img_raw || imgtype == pdf_img_ccitt || indjpeg)
1631    {
1632        keyword = "";
1633        if (image->height_pixel == pdc_undef)
1634            keyword = "height";
1635        else if (image->width_pixel == pdc_undef)
1636            keyword = "width";
1637        else
1638        {
1639            image->width = (float) image->width_pixel;
1640            image->height = (float) image->height_pixel;
1641        }
1642
1643        if (imgtype == pdf_img_ccitt)
1644        {
1645            image->components = 1;
1646            image->bpc = 1;
1647        }
1648        if (image->bpc == pdc_undef)
1649            keyword = "bpc";
1650        else if (image->components == pdc_undef)
1651            keyword = "components";
1652
1653        if (*keyword)
1654        {
1655	    pdc_set_errmsg(p->pdc, PDC_E_OPT_NOTFOUND, keyword, 0, 0, 0);
1656
1657            if (image->verbose)
1658		pdc_error(p->pdc, -1, 0, 0, 0, 0);
1659
1660            pdf_cleanup_image(p, imageslot);
1661            return -1;
1662        }
1663    }
1664
1665    /* set colorspace */
1666    if (colorize != pdc_undef)
1667    {
1668        image->colorspace = colorize;
1669    }
1670    else if (image->imagemask == pdc_true)
1671    {
1672        image->colorspace = (int) DeviceGray;
1673    }
1674    else
1675    {
1676        switch(image->components)
1677        {
1678            case 1:
1679            image->colorspace = DeviceGray;
1680            break;
1681
1682            case 3:
1683            image->colorspace = DeviceRGB;
1684            break;
1685
1686            case 4:
1687            image->colorspace = DeviceCMYK;
1688            break;
1689
1690            default:
1691            break;
1692        }
1693    }
1694
1695    /* try to open image file */
1696    if (image->reference == pdf_ref_direct)
1697    {
1698	strcpy(qualname, type);
1699	strcat(qualname, " ");
1700        image->fp = pdf_fopen(p, filename, qualname, PDC_FILE_BINARY);
1701
1702        if (image->fp == NULL)
1703        {
1704	    if (image->verbose)
1705		pdc_error(p->pdc, -1, 0, 0, 0, 0);
1706
1707	    pdf_cleanup_image(p, imageslot);
1708            return -1;
1709        }
1710    }
1711
1712    /* copy filename */
1713    image->filename = pdc_strdup(p->pdc, filename);
1714
1715
1716    /* call working function */
1717    switch (imgtype)
1718    {
1719        case pdf_img_bmp:
1720        retval = pdf_process_BMP_data(p, imageslot);
1721        break;
1722
1723        case pdf_img_ccitt:
1724        retval = pdf_process_CCITT_data(p, imageslot);
1725        break;
1726
1727        case pdf_img_gif:
1728        retval = pdf_process_GIF_data(p, imageslot);
1729        break;
1730
1731        case pdf_img_jpeg:
1732        retval = pdf_process_JPEG_data(p, imageslot);
1733        break;
1734
1735        case pdf_img_png:
1736        retval = pdf_process_PNG_data(p, imageslot);
1737        break;
1738
1739        default:
1740        case pdf_img_raw:
1741        retval = pdf_process_RAW_data(p, imageslot);
1742        break;
1743
1744        case pdf_img_tiff:
1745        retval = pdf_process_TIFF_data(p, imageslot);
1746        break;
1747    }
1748
1749    /* cleanup */
1750    if (retval == -1)
1751    {
1752        pdf_cleanup_image(p, imageslot);
1753    }
1754    else
1755    {
1756        if (image->fp)
1757            pdc_fclose(image->fp);
1758        image->fp = NULL;
1759    }
1760
1761    return retval;
1762}
1763