summaryrefslogtreecommitdiff
path: root/src/pdflib/pdflib/p_image.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdflib/pdflib/p_image.c')
-rw-r--r--src/pdflib/pdflib/p_image.c2253
1 files changed, 2253 insertions, 0 deletions
diff --git a/src/pdflib/pdflib/p_image.c b/src/pdflib/pdflib/p_image.c
new file mode 100644
index 0000000..fe95b1c
--- /dev/null
+++ b/src/pdflib/pdflib/p_image.c
@@ -0,0 +1,2253 @@
+/*---------------------------------------------------------------------------*
+ | PDFlib - A library for generating PDF on the fly |
+ +---------------------------------------------------------------------------+
+ | Copyright (c) 1997-2007 Thomas Merz and PDFlib GmbH. All rights reserved. |
+ +---------------------------------------------------------------------------+
+ | |
+ | This software is subject to the PDFlib license. It is NOT in the |
+ | public domain. Extended versions and commercial licenses are |
+ | available, please check http://www.pdflib.com. |
+ | |
+ *---------------------------------------------------------------------------*/
+
+/* $Id: p_image.c,v 1.1 2008/10/17 06:11:49 scuri Exp $
+ *
+ * PDFlib image routines
+ *
+ */
+
+#define P_IMAGE_C
+
+#include "p_intern.h"
+#include "p_color.h"
+#include "p_defopt.h"
+#include "p_font.h"
+#include "p_image.h"
+#include "p_layer.h"
+#include "p_tagged.h"
+
+static void
+pdf_init_image_struct(PDF *p, pdf_image *image)
+{
+ (void) p;
+
+ /********** option variables *************/
+ image->verbose = p->debug[(int) 'i'];
+ image->verbose = pdf_get_errorpolicy(p, NULL, image->verbose);
+ image->bitreverse = pdc_false;
+ image->bpc = pdc_undef;
+ image->components = pdc_undef;
+ image->height_pixel = pdc_undef;
+ image->ignoremask = pdc_false;
+ image->ignoreorient = pdc_false;
+ image->doinline = pdc_false;
+ image->interpolate = pdc_false;
+ image->invert = pdc_false;
+ image->jpegoptimize = pdc_true;
+ image->passthrough = pdc_undef;
+ image->K = 0;
+ image->imagemask = pdc_false;
+ image->mask = pdc_undef;
+ image->ri = AutoIntent;
+ image->page = 1;
+ image->reference = pdf_ref_direct;
+ image->width_pixel = pdc_undef;
+ image->topdown_save = pdc_false;
+ image->iconname = (char *) NULL;
+ /*****************************************/
+
+ image->orientation = 1;
+ image->transparent = pdc_false;
+ image->compression = pdf_comp_none;
+ image->predictor = pred_default;
+ image->in_use = pdc_false;
+ image->corrupt = pdc_false;
+ image->fp = (pdc_file *) NULL;
+ image->filename = (char *) NULL;
+ image->params = (char *) NULL;
+ image->dpi_x = 0;
+ image->dpi_y = 0;
+ image->strips = 1;
+ image->rowsperstrip = 1;
+ image->colorspace = pdc_undef;
+ image->dochandle = pdc_undef; /* this means "not a PDI page" */
+ image->use_raw = pdc_false;
+ image->pixelmode = pdc_undef;
+ image->type = pdf_img_auto;
+ image->transval[0] = 0;
+ image->transval[1] = 0;
+ image->transval[2] = 0;
+ image->transval[3] = 0;
+
+
+ /********* image-type specific stuff *****/
+ /* This is ugly, but we must do it here since both the TIFF and JPEG
+ * modules are affected.
+ */
+ image->info.jpeg.jpegifoffset = 0L;
+}
+
+void
+pdf_init_images(PDF *p)
+{
+ int im;
+
+ p->images_capacity = IMAGES_CHUNKSIZE;
+
+ p->images = (pdf_image *)
+ pdc_malloc(p->pdc,
+ sizeof(pdf_image) * p->images_capacity, "pdf_init_images");
+
+ for (im = 0; im < p->images_capacity; im++)
+ pdf_init_image_struct(p, &(p->images[im]));
+}
+
+void
+pdf_grow_images(PDF *p)
+{
+ int im;
+
+ p->images = (pdf_image *) pdc_realloc(p->pdc, p->images,
+ sizeof(pdf_image) * 2 * p->images_capacity, "pdf_grow_images");
+
+ for (im = p->images_capacity; im < 2 * p->images_capacity; im++)
+ pdf_init_image_struct(p, &(p->images[im]));
+
+ p->images_capacity *= 2;
+}
+
+void
+pdf_cleanup_image(PDF *p, int im)
+{
+ pdf_image *image = &p->images[im];
+
+ /* clean up parameter string if necessary */
+ if (image->params)
+ {
+ pdc_free(p->pdc, image->params);
+ image->params = NULL;
+ }
+
+ if (image->filename)
+ {
+ pdc_free(p->pdc, image->filename);
+ image->filename = NULL;
+ }
+
+ if (image->fp)
+ {
+ pdc_fclose(image->fp);
+ image->fp = NULL;
+ }
+
+ if (image->iconname)
+ {
+ pdc_free(p->pdc, image->iconname);
+ image->iconname = NULL;
+ }
+
+
+
+ /* type-specific cleanups */
+ if (image->type == pdf_img_gif)
+ pdf_cleanup_gif(p, image);
+
+ if (image->type == pdf_img_jpeg)
+ pdf_cleanup_jpeg(p, image);
+
+ /* free the image slot and prepare for next use */
+ pdf_init_image_struct(p, image);
+}
+
+void
+pdf_cleanup_images(PDF *p)
+{
+ int im;
+
+ if (!p->images)
+ return;
+
+ /* Free images which the caller left open */
+
+ /* When we think of inter-document survival of images,
+ ** we MUST NOT FORGET that the current TIFF algorithm
+ ** depends on contiguous image slots for the image strips!
+ */
+ for (im = 0; im < p->images_capacity; im++)
+ {
+ if (p->images[im].in_use) /* found used slot */
+ pdf_cleanup_image(p, im); /* free image descriptor */
+ }
+
+ pdc_free(p->pdc, p->images);
+ p->images = NULL;
+}
+
+void
+pdf_init_xobjects(PDF *p)
+{
+ int idx;
+
+ p->xobjects_number = 0;
+
+ if (p->xobjects == (pdf_xobject *) 0)
+ {
+ p->xobjects_capacity = XOBJECTS_CHUNKSIZE;
+
+ p->xobjects = (pdf_xobject *)
+ pdc_malloc(p->pdc, sizeof(pdf_xobject) * p->xobjects_capacity,
+ "pdf_init_xobjects");
+ }
+
+ for (idx = 0; idx < p->xobjects_capacity; idx++)
+ p->xobjects[idx].flags = 0;
+}
+
+int
+pdf_new_xobject(PDF *p, pdf_xobj_type type, pdc_id obj_id)
+{
+ static const char fn[] = "pdf_new_xobject";
+ int i, slot = p->xobjects_number++;
+
+ if (slot == p->xobjects_capacity)
+ {
+ p->xobjects = (pdf_xobject *) pdc_realloc(p->pdc, p->xobjects,
+ sizeof(pdf_xobject) * 2 * p->xobjects_capacity, fn);
+
+ for (i = p->xobjects_capacity; i < 2 * p->xobjects_capacity; i++)
+ p->xobjects[i].flags = 0;
+
+ p->xobjects_capacity *= 2;
+ }
+
+ if (obj_id == PDC_NEW_ID)
+ obj_id = pdc_begin_obj(p->out, PDC_NEW_ID);
+
+ p->xobjects[slot].obj_id = obj_id;
+ p->xobjects[slot].type = type;
+ p->xobjects[slot].flags = xobj_flag_used;
+
+ return slot;
+}
+
+pdc_id
+pdf_get_xobject(PDF *p, int im)
+{
+ if (im >= 0 && im < p->images_capacity)
+ {
+ pdf_image *img = &p->images[im];
+
+ if (img->in_use)
+ return p->xobjects[img->no].obj_id;
+ }
+ return PDC_BAD_ID;
+}
+
+void
+pdf_write_xobjects(PDF *p)
+{
+ if (p->xobjects_number > 0)
+ {
+ pdc_bool hit = pdc_false;
+ int i;
+
+ for (i = 0; i < p->xobjects_number; ++i)
+ {
+ if (p->xobjects[i].flags & xobj_flag_write)
+ {
+ if (!hit)
+ {
+ pdc_puts(p->out, "/XObject");
+ pdc_begin_dict(p->out);
+ hit = pdc_true;
+ }
+
+ pdc_printf(p->out, "/I%d", i);
+ pdc_objref(p->out, "", p->xobjects[i].obj_id);
+ p->xobjects[i].flags &= ~xobj_flag_write;
+ }
+ }
+
+ if (hit)
+ pdc_end_dict(p->out);
+ }
+}
+
+void
+pdf_get_page_xobjects(PDF *p, pdf_reslist *rl)
+{
+ int i;
+
+ for (i = 0; i < p->xobjects_number; i++) {
+ if (p->xobjects[i].flags & xobj_flag_write) {
+ p->xobjects[i].flags &= ~xobj_flag_write;
+ pdf_add_reslist(p, rl, i);
+ }
+ }
+}
+
+void
+pdf_mark_page_xobject(PDF *p, int n)
+{
+ p->xobjects[n].flags |= xobj_flag_write;
+}
+
+void
+pdf_cleanup_xobjects(PDF *p)
+{
+ if (p->xobjects) {
+ pdc_free(p->pdc, p->xobjects);
+ p->xobjects = NULL;
+ }
+}
+
+
+/* ---------------------------- put image ----------------------------------- */
+
+void
+pdf_put_inline_image(PDF *p, int im)
+{
+ static const char *fn = "pdf_put_inline_image";
+ pdf_image *image;
+ pdc_matrix m;
+ PDF_data_source *src;
+ int i;
+
+ image = &p->images[im];
+
+ /* Image object */
+
+ image->no = -1;
+
+ pdf__save(p);
+
+ pdc_scale_matrix(image->width, image->height, &m);
+
+ pdf_concat_raw(p, &m);
+
+ pdc_puts(p->out, "BI");
+
+ pdc_printf(p->out, "/W %d", (int) image->width);
+ pdc_printf(p->out, "/H %d", (int) image->height);
+
+ /* Acrobat 7 and 8 require /BPC even for image masks */
+ pdc_printf(p->out, "/BPC %d", image->bpc);
+
+ if (image->imagemask == pdc_true) {
+ pdc_puts(p->out, "/IM true");
+
+ } else if (image->colorspace != pdc_undef) {
+
+ switch (p->colorspaces[image->colorspace].type) {
+ case DeviceGray:
+ pdc_printf(p->out, "/CS/G");
+ break;
+
+ case DeviceRGB:
+ pdc_printf(p->out, "/CS/RGB");
+ break;
+
+ case DeviceCMYK:
+ pdc_printf(p->out, "/CS/CMYK");
+ break;
+
+ default:
+ pdc_error(p->pdc, PDF_E_INT_BADCS, fn,
+ pdc_errprintf(p->pdc, "%d", image->colorspace),
+ pdc_errprintf(p->pdc, "%d",
+ (int) p->colorspaces[image->colorspace].type),
+ 0);
+ break;
+ }
+ }
+
+ if (image->compression != pdf_comp_none) {
+ pdc_printf(p->out, "/F/%s",
+ pdc_get_keyword(image->compression, pdf_shortfilter_pdfkeylist));
+ }
+
+ /* prepare precompressed (raw) image data */
+ if (image->use_raw &&
+ (image->params ||
+ image->predictor != pred_default ||
+ image->compression == pdf_comp_ccitt)) {
+
+ pdc_printf(p->out, "/DP[<<");
+
+ /* write EarlyChange */
+ if (image->params)
+ pdc_puts(p->out, image->params);
+
+ if (image->compression == pdf_comp_ccitt) {
+ if (image->K != 0)
+ pdc_printf(p->out, "/K %d", image->K);
+ }
+
+ if (image->compression == pdf_comp_flate ||
+ image->compression == pdf_comp_lzw) {
+ if (image->predictor != pred_default) {
+ pdc_printf(p->out, "/Predictor %d", (int) image->predictor);
+ pdc_printf(p->out, "/Columns %d", (int) image->width);
+ if (image->bpc != 8)
+ pdc_printf(p->out, "/BitsPerComponent %d", image->bpc);
+
+ if (image->components != 1) /* 1 is default */
+ pdc_printf(p->out, "/Colors %d", image->components);
+ }
+ }
+
+ if (image->compression == pdf_comp_ccitt) {
+ if ((int) image->width != 1728) /* CCITT default width */
+ pdc_printf(p->out, "/Columns %d", (int) image->width);
+
+ /* /Rows is not required */
+ }
+ pdc_puts(p->out, ">>]"); /* DecodeParms dict and array */
+ }
+
+ if (image->ri != AutoIntent) {
+ pdc_printf(p->out, "/Intent/%s",
+ pdc_get_keyword(image->ri, pdf_renderingintent_pdfkeylist));
+ }
+
+ if (image->interpolate) {
+ pdc_puts(p->out, "/I true");
+ }
+
+ if (image->invert) {
+ pdc_puts(p->out, "/D[1 0");
+ for (i = 1; i < image->components; i++)
+ pdc_puts(p->out, " 1 0");
+ pdc_puts(p->out, "]ID\n");
+
+ } else {
+ pdc_puts(p->out, " ID\n");
+ }
+
+ /* Write the actual image data to the content stream */
+
+ src = &image->src;
+
+ /* We can't use pdf_copy_stream() here because it automatically
+ * generates a stream object, which is not correct for inline
+ * image data.
+ */
+ if (src->init)
+ src->init(p, src);
+
+ while (src->fill(p, src))
+ pdc_write(p->out, src->next_byte, src->bytes_available);
+
+ if (src->terminate)
+ src->terminate(p, src);
+
+ /* Acrobat requires whitespace between image data and "EI" */
+ pdc_puts(p->out, "\nEI\n");
+
+ pdf__restore(p);
+
+ /* Do the equivalent of PDF_close_image() since the image handle
+ * cannot be re-used anyway.
+ */
+ pdf_cleanup_image(p, im);
+}
+
+void
+pdf_put_image(PDF *p, int im, pdc_bool firststrip, pdc_bool checkcontentstream)
+{
+ static const char *fn = "pdf_put_image";
+ pdc_bool logg3 = pdc_logg_is_enabled(p->pdc, 3, trc_image);
+ pdc_id length_id;
+ pdf_image *image;
+ int i;
+ pdf_compression compression;
+
+ image = &p->images[im];
+
+ if (logg3)
+ pdc_logg(p->pdc, "\t\t\tput image %d to PDF file ...\n", im);
+
+ /* Images may also be written to the output before the first page */
+ if (checkcontentstream && PDF_GET_STATE(p) == pdf_state_page)
+ pdf_end_contents_section(p);
+
+
+
+ pdc_logg_cond(p->pdc, 2, trc_image,
+ "\tpdf_put_image:\n"
+ "\t\t\tim = %d\n"
+ "\t\t\timage->colorspace = %d\n",
+ im,
+ image->colorspace);
+
+ if (image->colorspace != pdc_undef)
+ pdc_logg_cond(p->pdc, 2, trc_image,
+ "\t\t\tcolor space type = %d\n",
+ (int) p->colorspaces[image->colorspace].type);
+
+ /* Image object */
+
+ image->no = pdf_new_xobject(p, image_xobject, PDC_NEW_ID);
+
+ pdc_begin_dict(p->out); /* XObject */
+
+ pdc_puts(p->out, "/Subtype/Image\n");
+
+ pdc_printf(p->out, "/Width %d\n", (int) image->width);
+ pdc_printf(p->out, "/Height %d\n", (int) fabs(image->height));
+
+ /*
+ * Transparency handling
+ */
+
+ /* Masking by color: single transparent color value */
+ if (image->transparent && image->colorspace != pdc_undef) {
+ pdf_colorspace *cs = &p->colorspaces[image->colorspace];
+
+ switch (cs->type) {
+ case Indexed:
+ case DeviceGray:
+ pdc_printf(p->out,"/Mask[%d %d]\n",
+ (int) image->transval[0], (int) image->transval[0]);
+ break;
+
+
+ case DeviceRGB:
+ pdc_printf(p->out,"/Mask[%d %d %d %d %d %d]\n",
+ (int) image->transval[0], (int) image->transval[0],
+ (int) image->transval[1], (int) image->transval[1],
+ (int) image->transval[2], (int) image->transval[2]);
+ break;
+
+ case DeviceCMYK:
+ pdc_printf(p->out,"/Mask[%d %d %d %d %d %d %d %d]\n",
+ (int) image->transval[0], (int) image->transval[0],
+ (int) image->transval[1], (int) image->transval[1],
+ (int) image->transval[2], (int) image->transval[2],
+ (int) image->transval[3], (int) image->transval[3]);
+ break;
+
+ default:
+ pdc_error(p->pdc, PDF_E_INT_BADCS, fn,
+ pdc_errprintf(p->pdc, "%d", image->colorspace),
+ pdc_errprintf(p->pdc, "%d",
+ (int) p->colorspaces[image->colorspace].type),
+ 0);
+ }
+
+ /* Masking by position: separate bitmap mask */
+ } else if (image->mask != pdc_undef && p->images[image->mask].bpc > 1) {
+ pdc_objref(p->out, "/SMask",
+ p->xobjects[p->images[image->mask].no].obj_id);
+
+ } else if (image->mask != pdc_undef) {
+ pdc_objref(p->out, "/Mask",
+ p->xobjects[p->images[image->mask].no].obj_id);
+ }
+
+ /*
+ * /BitsPerComponent is optional for image masks according to the
+ * PDF reference, but some viewers require it nevertheless.
+ * We must therefore always write it.
+ */
+ if (image->type != pdf_img_jpeg2000)
+ pdc_printf(p->out, "/BitsPerComponent %d\n", image->bpc);
+
+ if (image->imagemask) {
+ pdc_puts(p->out, "/ImageMask true\n");
+ if (image->type == pdf_img_jpeg2000)
+ pdc_puts(p->out, "/SMaskInData 1\n");
+
+ } else if (image->colorspace != pdc_undef) {
+
+ switch (p->colorspaces[image->colorspace].type) {
+ case DeviceGray:
+ break;
+
+ case DeviceRGB:
+ break;
+
+ case DeviceCMYK:
+ break;
+
+ case Indexed:
+ break;
+
+
+
+ default:
+ pdc_error(p->pdc, PDF_E_INT_BADCS, fn,
+ pdc_errprintf(p->pdc, "%d", image->colorspace),
+ pdc_errprintf(p->pdc, "%d",
+ (int) p->colorspaces[image->colorspace].type),
+ 0);
+ }
+
+ pdc_puts(p->out, "/ColorSpace");
+ pdf_write_colorspace(p, image->colorspace, pdc_false);
+ pdc_puts(p->out, "\n");
+ }
+
+ if (image->invert) {
+ pdc_puts(p->out, "/Decode[1 0");
+ for (i = 1; i < image->components; i++)
+ pdc_puts(p->out, " 1 0");
+ pdc_end_array(p->out);
+ }
+
+ if (image->ri != AutoIntent) {
+ pdc_printf(p->out, "/Intent/%s\n",
+ pdc_get_keyword(image->ri, pdf_renderingintent_pdfkeylist));
+ }
+
+ if (image->interpolate) {
+ pdc_puts(p->out, "/Interpolate true\n");
+ }
+
+ /* special case: referenced image data instead of direct data */
+ if (image->reference != pdf_ref_direct) {
+
+ if (image->compression != pdf_comp_none) {
+ pdc_printf(p->out, "/FFilter[/%s]\n",
+ pdc_get_keyword(image->compression, pdf_filter_pdfkeylist));
+ }
+
+ if (image->compression == pdf_comp_ccitt) {
+ pdc_puts(p->out, "/FDecodeParms[<<");
+
+ if ((int) image->width != 1728) /* CCITT default width */
+ pdc_printf(p->out, "/Columns %d", (int) image->width);
+
+ /*
+ pdc_printf(p->out, "/Rows %d", (int) fabs(image->height));
+ */
+
+ if (image->K != 0)
+ pdc_printf(p->out, "/K %d", image->K);
+
+ pdc_puts(p->out, ">>]\n");
+
+ }
+
+ if (image->reference == pdf_ref_file) {
+
+ /* LATER: make image file name platform-neutral:
+ * Change : to / on the Mac
+ * Change \ to / on Windows
+ */
+ pdc_puts(p->out, "/F");
+ pdc_put_pdfstring(p->out, image->filename, 0);
+ pdc_puts(p->out, "/Length 0");
+
+ } else if (image->reference == pdf_ref_url) {
+
+ pdc_puts(p->out, "/F<</FS/URL/F");
+ pdc_put_pdfstring(p->out, image->filename, 0);
+ pdc_puts(p->out, ">>/Length 0");
+ }
+
+ pdc_end_dict(p->out); /* XObject */
+
+ /* We must avoid pdc_begin/end_pdfstream() here in order to
+ * generate a really empty stream.
+ */
+ pdc_puts(p->out, "stream\n"); /* dummy image stream */
+ pdc_puts(p->out, "endstream\n");
+
+ pdc_end_obj(p->out); /* XObject */
+
+ if (PDF_GET_STATE(p) == pdf_state_page)
+ pdf_begin_contents_section(p);
+
+ return;
+ }
+
+ compression = image->compression;
+
+ /*
+ * Now the (more common) handling of actual image
+ * data to be included in the PDF output.
+ */
+
+ /* force compression if not a recognized precompressed image format */
+ if ((!image->use_raw || compression == pdf_comp_none) &&
+ pdc_get_compresslevel(p->out))
+ compression = pdf_comp_flate;
+
+ if (compression != pdf_comp_none)
+ pdc_printf(p->out, "/Filter/%s\n",
+ pdc_get_keyword(compression, pdf_filter_pdfkeylist));
+
+ /* prepare precompressed (raw) image data; avoid empty DecodeParms */
+ if (image->use_raw &&
+ (image->params ||
+ image->predictor != pred_default ||
+ compression == pdf_comp_ccitt)) {
+
+ pdc_printf(p->out, "/DecodeParms<<");
+
+ /* write EarlyChange */
+ if (image->params)
+ pdc_puts(p->out, image->params);
+
+ if (compression == pdf_comp_ccitt) {
+ if (image->K != 0)
+ pdc_printf(p->out, "/K %d", image->K);
+ }
+
+ if (compression == pdf_comp_flate || compression == pdf_comp_lzw) {
+ if (image->predictor != pred_default) {
+ pdc_printf(p->out, "/Predictor %d", (int) image->predictor);
+ pdc_printf(p->out, "/Columns %d", (int) image->width);
+ if (image->bpc != 8)
+ pdc_printf(p->out, "/BitsPerComponent %d", image->bpc);
+
+ if (image->components != 1) /* 1 is default */
+ pdc_printf(p->out, "/Colors %d", image->components);
+ }
+ }
+
+ if (compression == pdf_comp_ccitt) {
+ if ((int) image->width != 1728) /* CCITT default width */
+ pdc_printf(p->out, "/Columns %d", (int) image->width);
+
+ /* /Rows is not required */
+ }
+
+ pdc_puts(p->out, ">>\n"); /* DecodeParms dict */
+ }
+
+
+
+
+ /* Write the actual image data */
+ length_id = pdc_alloc_id(p->out);
+
+ pdc_objref(p->out, "/Length", length_id);
+ pdc_end_dict(p->out); /* XObject */
+
+ /* image data */
+
+ /*
+ * We must check "image->compression" here since this describes the
+ * actual status of the input data, as opposed to "compression"
+ * which describes the desired status of the output data.
+ */
+
+ pdf_copy_stream(p, &image->src,
+ !image->use_raw || image->compression == pdf_comp_none);
+
+ pdc_end_obj(p->out); /* XObject */
+
+ pdc_put_pdfstreamlength(p->out, length_id);
+
+ if (p->flush & pdc_flush_content)
+ pdc_flush_stream(p->out);
+
+ /*
+ * Write colormap information for indexed color spaces
+ */
+ if (firststrip && image->colorspace != pdc_undef &&
+ p->colorspaces[image->colorspace].type == Indexed) {
+ pdf_write_colormap(p, image->colorspace);
+ }
+
+ if (checkcontentstream && PDF_GET_STATE(p) == pdf_state_page)
+ pdf_begin_contents_section(p);
+
+ if (p->flush & pdc_flush_content)
+ pdc_flush_stream(p->out);
+}
+
+
+/* ---------------------------- fit image ----------------------------------- */
+
+void
+pdf__fit_image(PDF *p, int im, pdc_scalar x, pdc_scalar y, const char *optlist)
+{
+ pdf_image *image;
+ int legal_states;
+
+ pdf_check_handle(p, im, pdc_imagehandle);
+
+ image = &p->images[im];
+
+ if (PDF_GET_STATE(p) == pdf_state_glyph && !pdf_get_t3colorized(p) &&
+ image->imagemask == pdc_false)
+ legal_states = pdf_state_page | pdf_state_pattern | pdf_state_template;
+ else
+ legal_states = pdf_state_content;
+ PDF_CHECK_STATE(p, legal_states);
+
+ if (PDF_GET_STATE(p) == pdf_state_template && im == p->templ)
+ pdc_error(p->pdc, PDF_E_TEMPLATE_SELF,
+ pdc_errprintf(p->pdc, "%d", im), 0, 0, 0);
+
+ pdc_check_number(p->pdc, "x", x);
+ pdc_check_number(p->pdc, "y", y);
+
+ pdf_place_xobject(p, im, x, y, optlist);
+}
+
+void
+pdf_init_xobject_options(PDF *p, pdf_xobject_options *xo)
+{
+ xo->adjustpage = pdc_false;
+ xo->blind = pdc_false;
+ xo->filename = NULL;
+ xo->flags = 0;
+ xo->imagewarning = p->debug[(int) 'i'];
+ xo->ignoreorientation = pdc_false;
+ xo->im = -1;
+ xo->mask = 0;
+ xo->dpi[0] = 0;
+ xo->dpi[1] = 0;
+ xo->page = 1;
+ xo->scale[0] = 1;
+ xo->scale[1] = 1;
+}
+
+void
+pdf_get_xobject_options(PDF *p, pdf_xobject_options *xo, pdc_resopt *resopts)
+{
+ int inum;
+
+ (void) p;
+
+ if (!(xo->flags & is_block))
+ {
+ pdc_get_optvalues("adjustpage", resopts, &xo->adjustpage, NULL);
+
+ pdc_get_optvalues("blind", resopts, &xo->blind, NULL);
+ }
+
+ if (xo->flags & is_image)
+ {
+ if (pdc_get_optvalues("ignoreorientation", resopts,
+ &xo->ignoreorientation, NULL))
+ xo->mask |= (1L << xo_ignoreorientation);
+
+
+ inum = pdc_get_optvalues("dpi", resopts, xo->dpi, NULL);
+ if (inum)
+ {
+ if (inum == 1)
+ xo->dpi[1] = xo->dpi[0];
+ xo->mask |= (1L << xo_dpi);
+ }
+ }
+
+ if (xo->flags & is_block)
+ {
+ if (pdc_get_optvalues("imagewarning", resopts, &xo->imagewarning, NULL))
+ xo->mask |= (1L << xo_imagewarning);
+ }
+
+ inum = pdc_get_optvalues("scale", resopts, xo->scale, NULL);
+ if (inum)
+ {
+ if (inum == 1)
+ xo->scale[1] = xo->scale[0];
+ xo->mask |= (1L << xo_scale);
+ }
+}
+
+/* definitions of fit xobject options */
+static const pdc_defopt pdf_fit_xobject_options[] =
+{
+ PDF_XOBJECT_OPTIONS1
+ PDF_XOBJECT_OPTIONS2
+ PDF_XOBJECT_OPTIONS3
+ PDF_FIT_OPTIONS1
+ PDF_FIT_OPTIONS2
+ PDC_OPT_TERMINATE
+};
+
+pdc_resopt *
+pdf_parse_fitxobject_optlist(PDF *p, int im, pdf_xobject_options *xo,
+ pdf_fit_options *fit, const char *optlist)
+{
+ pdc_resopt *resopts = NULL;
+ pdf_image *image = &p->images[im];
+
+ /* initialize */
+ pdf_init_xobject_options(p, xo);
+ xo->im = im;
+ if (p->xobjects[image->no].type == image_xobject)
+ {
+ xo->flags |= is_image;
+ xo->dpi[0] = dpi_internal;
+ xo->dpi[1] = dpi_internal;
+ xo->ignoreorientation = image->ignoreorient;
+ }
+ pdf_init_fit_options(p, pdc_false, fit);
+ fit->flags |= is_image;
+
+ /* parsing option list */
+ if (optlist && strlen(optlist))
+ {
+ pdc_clientdata data;
+
+ pdf_set_clientdata(p, &data);
+ resopts = pdc_parse_optionlist(p->pdc, optlist,
+ pdf_fit_xobject_options, &data, pdc_true);
+
+ pdf_get_xobject_options(p, xo, resopts);
+ pdf_get_fit_options(p, pdc_false, fit, resopts);
+ }
+
+ return resopts;
+}
+
+void
+pdf_place_xobject(PDF *p, int im, pdc_scalar x, pdc_scalar y,
+ const char *optlist)
+{
+ pdf_xobject_options xo;
+ pdf_fit_options fit;
+
+ /* initialize */
+ pdf_parse_fitxobject_optlist(p, im, &xo, &fit, optlist);
+ fit.refpoint[0] = x;
+ fit.refpoint[1] = y;
+
+ /* put out xobject */
+ if (!xo.blind)
+ {
+ pdf_end_text(p);
+ pdf_begin_contents_section(p);
+
+
+
+ pdf__save(p);
+ }
+
+ pdf_fit_xobject_internal(p, &xo, &fit, NULL);
+
+ if (!xo.blind)
+ pdf__restore(p);
+}
+
+void
+pdf_fit_xobject_internal(PDF *p, pdf_xobject_options *xo, pdf_fit_options *fit,
+ pdc_matrix *immatrix)
+{
+ pdc_bool logg3 = pdc_logg_is_enabled(p->pdc, 3, trc_image);
+ pdf_image *image = &p->images[xo->im];
+ pdf_xobject_options xo_save;
+ pdc_rectangle matchrect;
+ pdf_fit_options fit_save;
+ pdc_matrix m, mm, sm, ctm_save;
+ pdc_vector tmpscale, elemscale, fitscale, purescale;
+ pdc_vector elemsize, mirror, shift, relpos;
+ pdc_vector polyline[5];
+ pdc_box fitbox, clipbox, elembox;
+ pdc_scalar x, y, ss;
+ pdc_scalar rowsize = 1, lastratio = 1;
+ pdc_scalar dpi_x, dpi_y, tx = 0, ty = 0, boxwidth, boxheight;
+ pdc_bool hasfitbox, kclip = pdc_false, kcliptiff = pdc_false;
+ int indangle, indmirror;
+ int is, ip, islast;
+ int imageno;
+
+ /* initialize */
+ tmpscale.x = 1;
+ tmpscale.y = 1;
+ if (image->mask != pdc_undef)
+ {
+ ctm_save = p->curr_ppt->gstate[p->curr_ppt->sl].ctm;
+ xo_save = *xo;
+ fit_save = *fit;
+ }
+ else
+ {
+ pdc_identity_matrix(&ctm_save);
+ }
+
+ /* box size */
+ boxwidth = fit->boxsize[0];
+ boxheight = fit->boxsize[1];
+ hasfitbox = boxwidth > PDC_FLOAT_PREC && boxheight > PDC_FLOAT_PREC;
+
+ /* element size */
+ elemsize.x = fabs(image->width);
+ elemsize.y = fabs(image->height);
+
+ if (logg3)
+ pdc_logg(p->pdc,
+ "\t\t\tfitbox size: width=%g, height=%g\n"
+ "\t\t\telement size: width=%g, height=%g\n",
+ boxwidth, boxheight, elemsize.x, elemsize.y);
+
+ /* clipping */
+ if (!kclip)
+ {
+ kclip = pdf_get_mbox_clipping(p, fit->matchbox, elemsize.x, elemsize.y,
+ &clipbox);
+ }
+
+ if (logg3 && kclip)
+ pdc_logg(p->pdc,
+ "\t\t\tclip box: llx=%g, lly=%g, urx=%g, ury=%g\n",
+ clipbox.ll.x, clipbox.ll.y, clipbox.ur.x, clipbox.ur.y);
+
+ /* TIFF image orientation */
+ if (image->orientation != 1 && !xo->ignoreorientation)
+ {
+ /* Tag Orientation = 1, 2, 3, 4, 5, 6, 7, 8 */
+ const int addangle[8] = {0, 0, 180, 180, 90, 270, 270, 90};
+ const int rowmirror[8] = {1, -1, 1, -1, -1, 1, -1, 1};
+
+ if (logg3)
+ pdc_logg(p->pdc, "\t\t\torientation tag: %d\n", image->orientation);
+
+ is = image->orientation - 1;
+
+ fit->orientate += addangle[is];
+ if (fit->orientate >= 360)
+ fit->orientate -= 360;
+ tmpscale.x = rowmirror[is];
+
+ if (kclip)
+ {
+ switch (addangle[is])
+ {
+ default:
+ elembox = clipbox;
+ break;
+
+ case 90:
+ elembox.ll.x = clipbox.ll.y;
+ elembox.ll.y = elemsize.x - clipbox.ur.x;
+ elembox.ur.x = clipbox.ur.y;
+ elembox.ur.y = elemsize.x - clipbox.ll.x;
+ break;
+
+ case 180:
+ elembox.ll.x = elemsize.x - clipbox.ur.x;
+ elembox.ll.y = elemsize.y - clipbox.ur.y;
+ elembox.ur.x = elemsize.x - clipbox.ll.x;
+ elembox.ur.y = elemsize.y - clipbox.ll.y;
+ break;
+
+ case 270:
+ elembox.ll.x = elemsize.y - clipbox.ur.y;
+ elembox.ll.y = clipbox.ll.x;
+ elembox.ur.x = elemsize.y - clipbox.ll.y;
+ elembox.ur.y = clipbox.ur.x;
+ break;
+ }
+ clipbox = elembox;
+
+ if (tmpscale.x == -1)
+ {
+ clipbox.ll.x = elemsize.x - elembox.ur.x;
+ clipbox.ur.x = elemsize.x - elembox.ll.x;
+ }
+ }
+ }
+
+ /* Compensate inverted direction handling in TIFFReadRGBAImageOriented() */
+ if (!image->use_raw && image->pixelmode == pdc_true)
+ {
+ tmpscale.y = -1;
+ elembox = clipbox;
+ clipbox.ll.y = elemsize.y - elembox.ur.y;
+ clipbox.ur.y = elemsize.y - elembox.ll.y;
+ }
+
+ if (logg3 && kclip)
+ pdc_logg(p->pdc,
+ "\t\t\tclip box: llx=%g, lly=%g, urx=%g, ury=%g "
+ "(corrected)\n",
+ clipbox.ll.x, clipbox.ll.y, clipbox.ur.x, clipbox.ur.y);
+
+ /* image scale */
+ elemscale.x = tmpscale.x * xo->scale[0];
+ elemscale.y = tmpscale.y * xo->scale[1];
+
+ if (logg3)
+ pdc_logg(p->pdc,
+ "\t\t\telement scaling: sx=%g, sy=%g "
+ "(user, correction mirroring)\n",
+ elemscale.x, elemscale.y);
+
+ /* element size */
+ elemsize.x = fabs(clipbox.ur.x - clipbox.ll.x);
+ elemsize.y = fabs(clipbox.ur.y - clipbox.ll.y);
+
+ /* calculation of image scale and size */
+ if (xo->flags & is_image)
+ {
+ tmpscale.x = 1.0;
+ tmpscale.y = 1.0;
+ if (xo->dpi[0] == dpi_internal)
+ {
+ dpi_x = image->dpi_x;
+ dpi_y = image->dpi_y;
+ if (dpi_x > 0 && dpi_y > 0)
+ {
+ tmpscale.x = 72.0 / dpi_x;
+ tmpscale.y = 72.0 / dpi_y;
+ }
+ else if (dpi_x < 0 && dpi_y < 0)
+ {
+ tmpscale.y = dpi_y / dpi_x;
+ }
+ }
+ else if (xo->dpi[0] > 0)
+ {
+ tmpscale.x = 72.0 / xo->dpi[0];
+ tmpscale.y = 72.0 / xo->dpi[1];
+ }
+
+ elemscale.x *= tmpscale.x;
+ elemscale.y *= tmpscale.y;
+ rowsize = elemscale.y * image->rowsperstrip;
+
+ if (logg3)
+ pdc_logg(p->pdc,
+ "\t\t\telement scaling: sx=%g, sy=%g "
+ "(relating to 72dpi)\n",
+ tmpscale.x, tmpscale.y);
+ }
+
+ /* pure scaling without mirroring */
+ purescale.x = fabs(elemscale.x);
+ purescale.y = fabs(elemscale.y);
+
+ /* element size */
+ elemsize.x *= purescale.x;
+ elemsize.y *= purescale.y;
+
+ if (logg3)
+ pdc_logg(p->pdc,
+ "\t\t\telement size: width=%g, height=%g (scaled)\n",
+ elemsize.x, elemsize.y);
+
+ if (xo->flags & is_image)
+ {
+ elemscale.x *= image->width;
+ elemscale.y *= image->height;
+ lastratio = (elemscale.y / rowsize) - (image->strips - 1);
+ }
+
+ /* mirroring */
+ indmirror = 0;
+ if (elemscale.x < 0 && elemscale.y < 0)
+ indmirror = 2;
+ else if (elemscale.x < 0)
+ indmirror = 1;
+ else if (elemscale.y < 0)
+ indmirror = 3;
+
+ /* orientation */
+ indangle = fit->orientate / 90;
+ if (indangle % 2)
+ {
+ ss = elemsize.x;
+ elemsize.x = elemsize.y;
+ elemsize.y = ss;
+ }
+
+ /* box for fitting */
+ fitbox.ll.x = 0;
+ fitbox.ll.y = 0;
+ fitbox.ur.x = boxwidth;
+ fitbox.ur.y = boxheight;
+
+ /* relative position */
+ relpos.x = fit->position[0] / 100.0;
+ relpos.y = fit->position[1] / 100.0;
+
+ /* calculate image box */
+ if (fit->fitmethod == pdc_tauto)
+ fit->fitmethod = pdc_meet;
+ pdc_place_element(fit->fitmethod, 1.0, &fitbox, &relpos,
+ &elemsize, &relpos, &elembox, &fitscale);
+
+ if (logg3)
+ pdc_logg(p->pdc,
+ "\t\t\telement scaling: sx=%g, sy=%g "
+ "(relating to fitbox)\n",
+ fitscale.x, fitscale.y);
+
+ /* reference point */
+ x = fit->refpoint[0];
+ y = fit->refpoint[1];
+
+
+ /* adjust page size */
+ if (!xo->blind && xo->adjustpage && PDF_GET_STATE(p) == pdf_state_page)
+ {
+ pdc_scalar urx, ury, width, height, theight;
+
+ urx = 2 * x + elembox.ur.x;
+ ury = 2 * y + elembox.ur.y;
+ pdc_transform_point(&p->curr_ppt->gstate[p->curr_ppt->sl].ctm,
+ urx, ury, &width, &theight);
+ height = (p->ydirection > 0) ? theight
+ : pdf_get_pageheight(p) - p->ydirection * theight;
+
+ if (height < p->ydirection * theight / 2.0)
+ pdc_error(p->pdc, PDF_E_IMAGE_NOADJUST, 0, 0, 0, 0);
+
+ width = fabs(width);
+ height = fabs(height);
+
+ if ((width < PDF_ACRO_MINPAGE || width > PDF_ACRO_MAXPAGE ||
+ height < PDF_ACRO_MINPAGE || height > PDF_ACRO_MAXPAGE))
+ pdc_warning(p->pdc, PDF_E_PAGE_SIZE_ACRO, 0, 0, 0, 0);
+
+ pdf_set_pagebox(p, pdf_mediabox, 0, 0, width, height);
+ pdf_set_pagebox(p, pdf_artbox, 0, 0, 0, 0);
+ pdf_set_pagebox(p, pdf_bleedbox, 0, 0, 0, 0);
+ pdf_set_pagebox(p, pdf_cropbox, 0, 0, 0, 0);
+ pdf_set_pagebox(p, pdf_trimbox, 0, 0, 0, 0);
+ }
+
+ /* reference point */
+ pdc_translation_matrix(x, y, &m);
+
+ /* optional rotation */
+ if (fabs(fit->rotate) > PDC_FLOAT_PREC)
+ {
+ pdc_rotation_matrix(p->ydirection * fit->rotate, &mm);
+ pdc_multiply_matrix(&mm, &m);
+ }
+
+ /* output after translation and rotation */
+ if (!xo->blind)
+ {
+ /* new CTM */
+ if (fit->showborder ||
+ fit->fitmethod == pdc_clip || fit->fitmethod == pdc_slice)
+ {
+ pdf_concat_raw(p, &m);
+ pdc_identity_matrix(&m);
+ }
+
+ /* show border */
+ if (fit->showborder)
+ {
+ pdf__rect(p, 0, 0, boxwidth, boxheight);
+ pdf__stroke(p);
+ }
+
+ /* clipping */
+ if (fit->fitmethod == pdc_clip || fit->fitmethod == pdc_slice)
+ {
+ pdc_scalar cw = boxwidth;
+ pdc_scalar ch = boxheight;
+
+ if (cw < PDC_FLOAT_PREC)
+ cw = PDF_ACRO_MAXPAGE;
+ if (ch < PDC_FLOAT_PREC)
+ ch = PDF_ACRO_MAXPAGE;
+ pdf__rect(p, 0, 0, cw, ch);
+ pdf__clip(p);
+ }
+ }
+
+ /* translation of element box */
+ elembox.ll.y *= p->ydirection;
+ elembox.ur.y *= p->ydirection;
+ pdc_box2polyline(NULL, &elembox, polyline);
+ ip = indangle + indmirror;
+ if (ip >= 4) ip -= 4;
+ tx = polyline[ip].x;
+ ty = polyline[ip].y;
+ pdc_translation_matrix(tx, ty, &mm);
+ pdc_multiply_matrix(&mm, &m);
+ boxwidth = elembox.ur.x - elembox.ll.x;
+ boxheight = elembox.ur.y - elembox.ll.y;
+
+ /* orientation of image */
+ if (fit->orientate != 0)
+ {
+ pdc_rotation_matrix(p->ydirection * fit->orientate, &mm);
+ pdc_multiply_matrix(&mm, &m);
+ if (indangle % 2)
+ {
+ ss = fitscale.x;
+ fitscale.x = fitscale.y;
+ fitscale.y = ss;
+
+ ss = boxwidth;
+ boxwidth = p->ydirection * boxheight;
+ boxheight = p->ydirection * ss;
+ }
+ }
+
+ /* mirroring of image */
+ mirror.x = elemscale.x * fitscale.x;
+ elemscale.x = fabs(mirror.x);
+ mirror.x /= elemscale.x;
+ if (image->strips == 1)
+ mirror.y = p->ydirection * elemscale.y * fitscale.y;
+ else
+ mirror.y = p->ydirection * rowsize * fitscale.y;
+ elemscale.y = fabs(mirror.y);
+ mirror.y /= elemscale.y;
+ pdc_scale_matrix(mirror.x, mirror.y, &mm);
+ pdc_multiply_matrix(&mm, &m);
+
+ if (logg3)
+ pdc_logg(p->pdc,
+ "\t\t\tcumulative mirroring: mx=%g, my=%g\n",
+ mirror.x, mirror.y);
+
+ /* matchbox or clip path */
+ if (!xo->blind && (fit->matchbox || kclip || kcliptiff))
+ {
+ pdf_concat_raw(p, &m);
+ pdc_identity_matrix(&m);
+
+ if (fit->matchbox)
+ {
+ matchrect.llx = 0;
+ matchrect.lly = 0;
+ matchrect.urx = boxwidth;
+ matchrect.ury = p->ydirection * boxheight;
+ pdf_set_mbox_rectangle(p, fit->matchbox, &matchrect, 0);
+ pdf_draw_mbox_rectangle(p, fit->matchbox, mbox_area | mbox_border);
+
+ pdf_add_page_mbox(p, fit->matchbox);
+ }
+
+ /* displacement of image because of clipping */
+ shift = clipbox.ll;
+ purescale.x *= fitscale.x;
+ purescale.y *= fitscale.y;
+ if (kclip)
+ {
+ shift.x *= -purescale.x;
+ shift.y *= -purescale.y;
+ }
+
+ if (kclip)
+ {
+ /* user clipping path */
+ pdf__rect(p, 0, 0, boxwidth, boxheight);
+ pdf__clip(p);
+ }
+
+ if (kclip)
+ {
+ pdc_translation_matrix(shift.x, shift.y, &mm);
+ pdc_multiply_matrix(&mm, &m);
+ }
+ }
+
+ /* scaling of image */
+ pdc_scale_matrix(elemscale.x, elemscale.y, &mm);
+ pdc_multiply_matrix(&mm, &m);
+
+ /* ctm */
+ if (xo->blind)
+ {
+ if (immatrix == NULL)
+ mm = p->curr_ppt->gstate[p->curr_ppt->sl].ctm;
+ else
+ mm = *immatrix;
+ pdc_multiply_matrix(&m, &mm);
+ }
+ else
+ {
+ pdf_concat_raw(p, &m);
+ mm = p->curr_ppt->gstate[p->curr_ppt->sl].ctm;
+ }
+
+ pdc_logg_cond(p->pdc, 5, trc_image,
+ "\t\t\tCTM components of image %s\"%s\":\n"
+ "\t\t\ta = %f\n"
+ "\t\t\tb = %f\n"
+ "\t\t\tc = %f\n"
+ "\t\t\td = %f\n"
+ "\t\t\te = %f\n"
+ "\t\t\tf = %f\n",
+ image->imagemask ? "mask " : "",
+ image->filename, mm.a, mm.b, mm.c, mm.d, mm.e, mm.f);
+
+ if (!xo->blind)
+ pdf_cleanup_fit_options(p, fit);
+
+ /* check image orientation */
+ if (immatrix != NULL)
+ {
+ *immatrix = mm;
+ return;
+ }
+ if (image->mask != pdc_undef)
+ {
+ sm = ctm_save;
+ xo_save.im = image->mask;
+ xo_save.blind = pdc_true;
+ pdf_fit_xobject_internal(p, &xo_save, &fit_save, &sm);
+
+ if ((sm.a * mm.a < 0) || (sm.b * mm.b < 0) ||
+ (sm.c * mm.c < 0) || (sm.d * mm.d < 0))
+ {
+ pdc_error(p->pdc, PDF_E_IMAGE_NOMATCH,
+ p->images[image->mask].filename, image->filename, 0, 0);
+ }
+ }
+
+ if (!(xo->flags & is_image) && !xo->blind)
+ {
+ pdf_reset_gstate(p);
+ pdf_reset_tstate(p);
+ }
+
+
+ if (!xo->blind)
+ {
+ /* last strip first */
+ if (image->strips > 1 && lastratio != 1.0)
+ {
+ pdc_scale_matrix(1, lastratio, &m);
+ pdf_concat_raw(p, &m);
+ }
+
+ /* put out image strips separately if available */
+ islast = image->strips - 1;
+ imageno = image->no + islast;
+ for (is = islast; is >= 0; is--)
+ {
+ pdc_printf(p->out, "/I%d Do\n", imageno);
+ p->xobjects[imageno].flags |= xobj_flag_write;
+ if (image->strips > 1 && is > 0)
+ {
+ pdc_translation_matrix(0, 1, &m);
+ if (is == islast && lastratio != 1.0)
+ {
+ pdc_scale_matrix(1, (1.0 / lastratio), &sm);
+ pdc_multiply_matrix(&sm, &m);
+ }
+ pdf_concat_raw(p, &m);
+ imageno--;
+ }
+ }
+ if (image->mask != pdc_undef)
+ p->xobjects[p->images[image->mask].no].flags |= xobj_flag_write;
+ }
+}
+
+
+/* ---------------------------- info image --------------------------------- */
+
+void
+pdf_get_image_size(PDF *p, int im, pdc_scalar *width, pdc_scalar *height)
+{
+ pdf_image *image;
+
+ pdf_check_handle(p, im, pdc_imagehandle);
+ image = &p->images[im];
+
+ if (image->orientation < 5 || image->ignoreorient)
+ {
+ if (width)
+ *width = image->width;
+ if (height)
+ *height = fabs(image->height);
+ }
+ else
+ {
+ if (width)
+ *width = fabs(image->height);
+ if (height)
+ *height = image->width;
+ }
+}
+
+void
+pdf_get_image_resolution(PDF *p, int im, pdc_scalar *dpi_x, pdc_scalar *dpi_y)
+{
+ pdf_image *image;
+
+ pdf_check_handle(p, im, pdc_imagehandle);
+ image = &p->images[im];
+
+ if (image->orientation < 5 || image->ignoreorient)
+ {
+ if (dpi_x)
+ *dpi_x = image->dpi_x;
+ if (dpi_y)
+ *dpi_y = image->dpi_y;
+ }
+ else
+ {
+ if (dpi_x)
+ *dpi_x = image->dpi_y;
+ if (dpi_y)
+ *dpi_y = image->dpi_x;
+ }
+}
+
+
+const char *
+pdf_get_image_filename(PDF *p, pdf_image *image)
+{
+ return pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, image->filename);
+}
+
+
+/* ---------------------------- load image --------------------------------- */
+
+static const pdc_keyconn pdf_extension_names[] =
+{
+ {".bmp", pdf_img_bmp},
+ {".ccitt", pdf_img_ccitt},
+ {".g3", pdf_img_ccitt},
+ {".g4", pdf_img_ccitt},
+ {".fax", pdf_img_ccitt},
+ {".gif", pdf_img_gif},
+ {".jpg", pdf_img_jpeg},
+ {".jpeg", pdf_img_jpeg},
+ {".jpx", pdf_img_jpeg2000},
+ {".jp2", pdf_img_jpeg2000},
+ {".jpf", pdf_img_jpeg2000},
+ {".jpm", pdf_img_jpeg2000},
+ {".j2k", pdf_img_jpeg2000},
+ {".png", pdf_img_png},
+ {".raw", pdf_img_raw},
+ {".tif", pdf_img_tiff},
+ {".tiff", pdf_img_tiff},
+ {NULL, 0}
+};
+
+/* allowed values for options 'bpc' */
+static const pdc_keyconn pdf_bpcvalues[] =
+{
+ {"1", 1}, {"2", 2}, {"4", 4}, {"8", 8}, {"16", 16}, {NULL, 0}
+};
+
+/* allowed values for options 'components' */
+static const pdc_keyconn pdf_compvalues[] =
+{
+ {"1", 1}, {"3", 3}, {"4", 4}, {NULL, 0}
+};
+
+#define PDF_OPIOPT_FLAG PDC_OPT_UNSUPP
+#define PDF_ICCOPT_FLAG PDC_OPT_UNSUPP
+#define PDF_CLIPPATH_FLAG PDC_OPT_UNSUPP
+
+#define PDF_METADATA_FLAG PDC_OPT_UNSUPP
+
+#define PDF_LAYER_FLAG PDC_OPT_UNSUPP
+
+/* definitions of open image options */
+static const pdc_defopt pdf_open_image_options[] =
+{
+ {"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1,
+ 0.0, PDF_MAX_NAMESTRING, NULL},
+
+ {"bitreverse", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"bpc", pdc_integerlist, PDC_OPT_INTLIST, 1, 1, 1.0, 16.0, pdf_bpcvalues},
+
+ {"components", pdc_integerlist, PDC_OPT_INTLIST, 1, 1, 1.0, 4.0,
+ pdf_compvalues},
+
+ {"height", pdc_integerlist, 0, 1, 1, 1.0, PDC_INT_MAX, NULL},
+
+ {"width", pdc_integerlist, 0, 1, 1, 1.0, PDC_INT_MAX, NULL},
+
+ {"honoriccprofile", pdc_booleanlist, PDF_ICCOPT_FLAG, 1, 1, 0.0, 0.0, NULL},
+
+ /* ordering of the next three options is significant */
+
+ {"iccprofile", pdc_iccprofilehandle, PDF_ICCOPT_FLAG, 1, 1, 1.0, 0.0, NULL},
+
+ {"colorize", pdc_colorhandle, PDC_OPT_IGNOREIF1, 1, 1, 0.0, 0.0, NULL},
+
+ {"mask", pdc_booleanlist, PDC_OPT_IGNOREIF2, 1, 1, 0.0, 0.0, NULL},
+
+ {"honorclippingpath", pdc_booleanlist, PDF_CLIPPATH_FLAG, 1, 1,
+ 0.0, 0.0, NULL},
+
+ {"clippingpathname", pdc_stringlist, PDF_CLIPPATH_FLAG, 1, 1,
+ 1.0, PDC_INT_MAX, NULL},
+
+ {"ignoremask", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"ignoreorientation", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ /* deprecated */
+ {"imagewarning", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"inline", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"interpolate", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"invert", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"jpegoptimize", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"passthrough", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"K", pdc_integerlist, 0, 1, 1, -1.0, 1.0, NULL},
+
+ {"masked", pdc_imagehandle, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"page", pdc_integerlist, 0, 1, 1, 1.0, PDC_INT_MAX, NULL},
+
+ {"renderingintent", pdc_keywordlist, 0, 1, 1, 0.0, 0.0,
+ pdf_renderingintent_pdfkeylist},
+
+ {"reftype", pdc_keywordlist, 0, 1, 1, 0.0, 0.0, pdf_reftype_keys},
+
+ {"template", pdc_booleanlist, 0, 1, 1, 0.0, 0.0, NULL},
+
+ {"iconname", pdc_stringlist, 0, 1, 1,
+ 1.0, PDF_MAX_NAMESTRING, NULL},
+
+ {"OPI-1.3", pdc_stringlist, PDF_OPIOPT_FLAG, 1, 1,
+ 0.0, PDC_INT_MAX, NULL},
+
+ {"OPI-2.0", pdc_stringlist, PDF_OPIOPT_FLAG | PDC_OPT_IGNOREIF1, 1, 1,
+ 0.0, PDC_INT_MAX, NULL},
+
+ {"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1,
+ 0.0, PDC_INT_MAX, NULL},
+
+ {"layer", pdc_layerhandle, PDF_LAYER_FLAG, 1, 1,
+ 0.0, 0.0, NULL},
+
+ PDF_ERRORPOLICY_OPTION
+
+ PDC_OPT_TERMINATE
+};
+
+int
+pdf__load_image(
+ PDF *p,
+ const char *type,
+ const char *filename,
+ const char *optlist)
+{
+ const char *keyword = NULL, *stemp1 = NULL, *stemp2 = NULL, *stemp3 = NULL;
+ char qualname[32], uptype[16], testfilename[PDC_FILENAMELEN + 1];
+ pdc_clientdata data;
+ pdc_resopt *resopts;
+ pdc_encoding htenc;
+ int htcp;
+ pdf_image_type imgtype;
+ pdc_file *fp = NULL;
+ int colorize = pdc_undef;
+ pdf_image *image;
+ pdc_bool indjpeg = pdc_false;
+ pdc_bool templ = pdc_false;
+ pdc_bool verbose = p->debug[(int) 'i'];
+ int legal_states = 0;
+ int i, k, inum, imageslot, retval = -1, errcode = 0;
+
+ if (type == NULL || *type == '\0')
+ pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "type", 0, 0, 0);
+
+ /* parsing image type */
+ k = pdc_get_keycode_ci(type, pdf_image_keylist);
+ if (k == PDC_KEY_NOTFOUND)
+ pdc_error(p->pdc, PDC_E_ILLARG_STRING, "type", type, 0, 0);
+ imgtype = (pdf_image_type) k;
+ type = pdc_get_keyword(imgtype, pdf_image_keylist);
+
+ verbose = pdf_get_errorpolicy(p, NULL, verbose);
+
+ /* filename must be already converted to UTF-8 */
+ pdc_logg_cond(p->pdc, 1, trc_image, "\tImage file: \"%s\"\n", filename);
+
+ /* search for image file */
+ fp = pdc_fsearch_fopen(p->pdc, filename, NULL, "image ", PDC_FILE_BINARY);
+
+ /* automatic check */
+ if (imgtype == pdf_img_auto)
+ {
+ pdf_tiff_info tiff_info;
+
+ /* search for files with other extensions */
+ if (fp == NULL)
+ {
+ pdc_logg_cond(p->pdc, 1, trc_image,
+ "\tImage file not found; searching for files "
+ "with alternative extensions\n");
+
+ for (i = 0; i < 2; i++)
+ {
+ for (k = 0; k < 100; k++)
+ {
+ const char *extension = pdf_extension_names[k].word;
+ if (extension)
+ {
+ strcpy(testfilename, filename);
+ strcpy(uptype, extension);
+ if (i)
+ pdc_strtoupper(uptype);
+ strcat(testfilename, uptype);
+
+ fp = pdc_fsearch_fopen(p->pdc, testfilename, NULL,
+ "image ", PDC_FILE_BINARY);
+ if (fp != NULL)
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (fp != NULL)
+ break;
+ }
+
+ if (fp != NULL)
+ {
+ filename = (const char *) testfilename;
+ pdc_logg_cond(p->pdc, 1, trc_image,
+ "\tImage file \"%s\" found\n", filename);
+ }
+ else
+ {
+ fp = pdc_fsearch_fopen(p->pdc, filename, NULL, "image ",
+ PDC_FILE_BINARY);
+ }
+ }
+
+ /* automatic type check */
+ if (fp != NULL)
+ {
+ if (pdf_is_BMP_file(p, fp))
+ imgtype = pdf_img_bmp;
+ else if (pdf_is_GIF_file(p, fp))
+ imgtype = pdf_img_gif;
+ else if (pdf_is_PNG_file(p, fp))
+ imgtype = pdf_img_png;
+ else if (pdf_is_TIFF_file(p, fp, &tiff_info, pdc_true))
+ imgtype = pdf_img_tiff;
+ else if (pdf_is_JPEG_file(p, fp))
+ imgtype = pdf_img_jpeg;
+ else if (pdf_is_JPX_file(p, fp))
+ imgtype = pdf_img_jpeg2000;
+ else
+ {
+ pdc_fclose(fp);
+
+ pdc_set_errmsg(p->pdc, PDF_E_IMAGE_UNKNOWN, filename, 0, 0, 0);
+
+ if (verbose)
+ PDC_RETHROW(p->pdc);
+
+ return -1;
+ }
+ type = pdc_get_keyword(imgtype, pdf_image_keylist);
+ }
+ }
+
+ if (fp == NULL)
+ {
+ if (verbose)
+ PDC_RETHROW(p->pdc);
+
+ return -1;
+ }
+ pdc_fclose(fp);
+
+ strcpy(uptype, type);
+ pdc_strtoupper(uptype);
+ pdc_logg_cond(p->pdc, 1, trc_image,
+ "\tImage type \"%s\" detected\n", uptype);
+
+ if (imgtype == pdf_img_jpeg2000)
+ {
+ pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_JPEG2000, 0, 0, 0, 0);
+
+ if (verbose)
+ PDC_RETHROW(p->pdc);
+
+ return -1;
+ }
+
+ /* find free slot */
+ for (imageslot = 0; imageslot < p->images_capacity; imageslot++)
+ if (!p->images[imageslot].in_use)
+ break;
+
+ if (imageslot == p->images_capacity)
+ pdf_grow_images(p);
+ image = &p->images[imageslot];
+
+ /* copy filename */
+ image->filename = pdc_strdup(p->pdc, filename);
+
+ /* inherit global flags */
+ image->verbose = verbose;
+ image->ri = p->rendintent;
+
+ /* parsing optlist */
+ if (optlist && strlen(optlist))
+ {
+ pdf_set_clientdata(p, &data);
+ resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_open_image_options,
+ &data, pdc_true);
+ /* save and check options */
+ keyword = "imagewarning";
+ pdc_get_optvalues(keyword, resopts, &image->verbose, NULL);
+ image->verbose = pdf_get_errorpolicy(p, resopts, image->verbose);
+ verbose = image->verbose;
+
+ keyword = "reftype";
+ if (pdc_get_optvalues(keyword, resopts, &inum, NULL))
+ {
+ image->reference = (pdf_ref_type) inum;
+ if (image->reference != pdf_ref_direct &&
+ imgtype != pdf_img_ccitt &&
+ imgtype != pdf_img_jpeg &&
+ imgtype != pdf_img_raw)
+ {
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword, uptype,
+ 0, 0);
+ image->reference = pdf_ref_direct;
+ }
+ }
+ indjpeg = (imgtype == pdf_img_jpeg &&
+ image->reference != pdf_ref_direct) ? pdc_true : pdc_false;
+
+ keyword = "bpc";
+ if (pdc_get_optvalues(keyword, resopts, &image->bpc, NULL))
+ {
+ if (imgtype != pdf_img_raw && !indjpeg)
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype,
+ 0, 0);
+ if (image->bpc == 16)
+ {
+ if (p->compatibility < PDC_1_5)
+ {
+ errcode = PDC_E_OPT_VERSION;
+ stemp1 = "bpc=16";
+ stemp2 = pdc_get_pdfversion(p->pdc, p->compatibility);
+ goto PDF_IMAGE_ERROR;
+ }
+ }
+ }
+
+ keyword = "components";
+ if (pdc_get_optvalues(keyword, resopts, &image->components, NULL))
+ {
+ if (imgtype != pdf_img_raw && !indjpeg)
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype,
+ 0, 0);
+ }
+
+ keyword = "height";
+ if (pdc_get_optvalues(keyword, resopts, &image->height_pixel, NULL))
+ {
+ if (imgtype != pdf_img_ccitt &&
+ imgtype != pdf_img_raw && !indjpeg)
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype,
+ 0, 0);
+ }
+
+ keyword = "width";
+ if (pdc_get_optvalues(keyword, resopts, &image->width_pixel, NULL))
+ {
+ if (imgtype != pdf_img_raw &&
+ imgtype != pdf_img_ccitt && !indjpeg)
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype,
+ 0, 0);
+ }
+
+ keyword = "bitreverse";
+ if (pdc_get_optvalues(keyword, resopts, &image->bitreverse, NULL))
+ {
+ if (image->bitreverse &&
+ (imgtype != pdf_img_ccitt || image->reference != pdf_ref_direct))
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype,
+ 0, 0);
+ }
+
+ keyword = "colorize";
+ if (pdc_get_optvalues(keyword, resopts, &colorize, NULL))
+ {
+ if (imgtype == pdf_img_jpeg2000)
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype,
+ 0, 0);
+ }
+
+
+ keyword = "ignoremask";
+ if (pdc_get_optvalues(keyword, resopts, &image->ignoremask, NULL))
+ {
+ if (imgtype == pdf_img_bmp ||
+ imgtype == pdf_img_ccitt ||
+ imgtype == pdf_img_raw)
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword, uptype,
+ 0, 0);
+ }
+
+ keyword = "ignoreorientation";
+ if (pdc_get_optvalues(keyword, resopts, &image->ignoreorient, NULL))
+ {
+ if (imgtype == pdf_img_tiff)
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword, uptype,
+ 0, 0);
+ }
+
+ keyword = "inline";
+ if (pdc_get_optvalues(keyword, resopts,
+ &image->doinline, NULL) && image->doinline)
+ {
+ if (imgtype != pdf_img_ccitt &&
+ imgtype != pdf_img_jpeg &&
+ imgtype != pdf_img_raw)
+ {
+ pdc_warning(p->pdc,
+ PDF_E_IMAGE_OPTUNSUPP, keyword, uptype, 0, 0);
+ image->doinline = pdc_false;
+ }
+ else if (image->reference != pdf_ref_direct)
+ {
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype,
+ 0, 0);
+ image->doinline = pdc_false;
+ }
+ }
+
+ keyword = "interpolate";
+ pdc_get_optvalues(keyword, resopts, &image->interpolate, NULL);
+
+
+ keyword = "invert";
+ if (pdc_get_optvalues(keyword, resopts, &image->invert, NULL))
+ {
+ if (imgtype == pdf_img_jpeg2000)
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype,
+ 0, 0);
+ }
+
+ keyword = "jpegoptimize";
+ pdc_get_optvalues(keyword, resopts, &image->jpegoptimize, NULL);
+
+ keyword = "passthrough";
+ pdc_get_optvalues(keyword, resopts, &image->passthrough, NULL);
+
+ keyword = "K";
+ if (pdc_get_optvalues(keyword, resopts, &image->K, NULL))
+ {
+ if (imgtype != pdf_img_ccitt)
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNREAS, keyword, uptype,
+ 0, 0);
+ }
+
+ keyword = "mask";
+ pdc_get_optvalues(keyword, resopts, &image->imagemask, NULL);
+
+
+ keyword = "masked";
+ if (pdc_get_optvalues(keyword, resopts, &image->mask, NULL))
+ {
+
+
+ if (!p->images[image->mask].in_use ||
+ p->images[image->mask].strips != 1 ||
+ (p->compatibility <= PDC_1_3 &&
+ (p->images[image->mask].imagemask != pdc_true ||
+ p->images[image->mask].bpc != 1)))
+ {
+ errcode = PDF_E_IMAGE_OPTBADMASK;
+ stemp1 = keyword;
+ stemp2 = pdc_errprintf(p->pdc, "%d", image->mask);
+ goto PDF_IMAGE_ERROR;
+ }
+
+ if (p->colorspaces[p->images[image->mask].colorspace].type !=
+ DeviceGray)
+ {
+ errcode = PDF_E_IMAGE_BADMASK;
+ stemp1 = pdc_errprintf(p->pdc, "%s",
+ p->images[image->mask].filename);
+ goto PDF_IMAGE_ERROR;
+ }
+ }
+
+ keyword = "renderingintent";
+ if (pdc_get_optvalues(keyword, resopts, &inum, NULL))
+ image->ri = (pdf_renderingintent) inum;
+
+ keyword = "page";
+ if (pdc_get_optvalues(keyword, resopts, &image->page, NULL))
+ {
+ if (imgtype != pdf_img_tiff)
+ {
+ if (image->page == 1)
+ {
+ pdc_warning(p->pdc, PDF_E_IMAGE_OPTUNSUPP, keyword,
+ uptype, 0, 0);
+ }
+ else
+ {
+ errcode = PDF_E_IMAGE_NOPAGE;
+ stemp1 = pdc_errprintf(p->pdc, "%d", image->page);
+ stemp2 = uptype;
+ stemp3 = pdc_errprintf(p->pdc, "%s", image->filename);
+ goto PDF_IMAGE_ERROR;
+ }
+ }
+ }
+
+ keyword = "template";
+ if (pdc_get_optvalues(keyword, resopts, &templ, NULL))
+ {
+ if (templ && image->doinline)
+ {
+ pdc_warning(p->pdc, PDC_E_OPT_IGNORE, keyword, "inline",
+ 0, 0);
+ templ = pdc_false;
+ }
+ }
+
+ htenc =
+ pdf_get_hypertextencoding_opt(p, resopts, &htcp, pdc_true);
+ keyword = "iconname";
+ if (pdf_get_opt_textlist(p, keyword, resopts, htenc, htcp, pdc_true,
+ NULL, &image->iconname, NULL))
+ {
+ if (image->doinline)
+ {
+ image->iconname = NULL;
+ pdc_warning(p->pdc, PDC_E_OPT_IGNORE, keyword, "inline",
+ 0, 0);
+ }
+ else
+ {
+ pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+ templ = pdc_true;
+ }
+ }
+
+
+
+ }
+
+ /* precise scope diagnosis */
+ if (image->doinline)
+ legal_states = pdf_state_content;
+ else if (templ)
+ legal_states = pdf_state_document;
+ else
+ legal_states = pdf_state_document | pdf_state_page | pdf_state_font;
+ PDF_CHECK_STATE(p, legal_states);
+
+ /* required options */
+ if (imgtype == pdf_img_raw || imgtype == pdf_img_ccitt || indjpeg)
+ {
+ keyword = "";
+ if (image->height_pixel == pdc_undef)
+ keyword = "height";
+ else if (image->width_pixel == pdc_undef)
+ keyword = "width";
+ else
+ {
+ image->width = image->width_pixel;
+ image->height = image->height_pixel;
+ }
+
+ if (imgtype == pdf_img_ccitt)
+ {
+ image->components = 1;
+ image->bpc = 1;
+ }
+ if (image->bpc == pdc_undef)
+ keyword = "bpc";
+ else if (image->components == pdc_undef)
+ keyword = "components";
+
+ if (*keyword)
+ {
+ errcode = PDC_E_OPT_NOTFOUND;
+ stemp1 = keyword;
+ goto PDF_IMAGE_ERROR;
+ }
+ }
+
+
+
+ /* set colorspace */
+ if (colorize != pdc_undef)
+ {
+ image->colorspace = colorize;
+ }
+ else if (image->imagemask == pdc_true)
+ {
+ image->colorspace = (int) DeviceGray;
+ }
+ else
+ {
+ switch(image->components)
+ {
+ case 1:
+ image->colorspace = DeviceGray;
+ break;
+
+ case 3:
+ image->colorspace = DeviceRGB;
+ break;
+
+ case 4:
+ image->colorspace = DeviceCMYK;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* try to open image file */
+ if (image->reference == pdf_ref_direct)
+ {
+ strcpy(qualname, uptype);
+ strcat(qualname, " ");
+ image->fp = pdc_fsearch_fopen(p->pdc, image->filename, NULL, qualname,
+ PDC_FILE_BINARY);
+ if (image->fp == NULL)
+ goto PDF_IMAGE_ERROR;
+ }
+
+
+ /* set image type */
+ image->type = imgtype;
+
+ /* call working function */
+ switch (imgtype)
+ {
+ case pdf_img_bmp:
+ retval = pdf_process_BMP_data(p, imageslot);
+ break;
+
+ case pdf_img_ccitt:
+ retval = pdf_process_CCITT_data(p, imageslot);
+ break;
+
+ case pdf_img_gif:
+ retval = pdf_process_GIF_data(p, imageslot);
+ break;
+
+ case pdf_img_jpeg:
+ if (image->passthrough == pdc_undef)
+ image->passthrough = pdc_false;
+ retval = pdf_process_JPEG_data(p, imageslot);
+ break;
+
+ case pdf_img_jpeg2000:
+ retval = pdf_process_JPX_data(p, imageslot);
+ break;
+
+ case pdf_img_png:
+ retval = pdf_process_PNG_data(p, imageslot);
+ break;
+
+ default:
+ case pdf_img_raw:
+ retval = pdf_process_RAW_data(p, imageslot);
+ break;
+
+ case pdf_img_tiff:
+ if (image->passthrough == pdc_undef)
+ image->passthrough = pdc_true;
+ retval = pdf_process_TIFF_data(p, imageslot);
+ break;
+ }
+
+ /* cleanup */
+ if (retval == -1)
+ {
+ pdf_cleanup_image(p, imageslot);
+
+ if (verbose)
+ PDC_RETHROW(p->pdc);
+ }
+ else
+ {
+ if (image->fp)
+ pdc_fclose(image->fp);
+ image->fp = NULL;
+
+ /* logging protocol */
+ if (pdc_logg_is_enabled(p->pdc, 1, trc_image))
+ {
+ pdc_scalar width, height, dpi_x, dpi_y;
+
+ pdf_get_image_size(p, imageslot, &width, &height);
+ pdf_get_image_resolution(p, imageslot, &dpi_x, &dpi_y);
+
+ pdc_logg(p->pdc, "\tImage width: %g pixel\n"
+ "\tImage height: %g pixel\n"
+ "\tImage x resolution: %g dpi\n"
+ "\tImage y resolution: %g dpi\n",
+ width, height, dpi_x, dpi_y);
+
+ if (imgtype == pdf_img_tiff)
+ pdc_logg(p->pdc, "\tOrientation tag: %d\n",
+ image->orientation);
+
+ }
+
+ if (templ)
+ {
+ retval = pdf_embed_image(p, imageslot);
+ pdf_cleanup_image(p, imageslot);
+ }
+ }
+
+ return retval;
+
+ PDF_IMAGE_ERROR:
+
+ pdf_cleanup_image(p, imageslot);
+
+ if (errcode)
+ pdc_set_errmsg(p->pdc, errcode, stemp1, stemp2, stemp3, 0);
+ if (verbose)
+ PDC_RETHROW(p->pdc);
+
+ return retval;
+}
+
+void
+pdf__close_image(PDF *p, int image)
+{
+ pdf_check_handle(p, image, pdc_imagehandle);
+ pdf_cleanup_image(p, image);
+}
+
+
+#define MAX_THUMBNAIL_SIZE 106
+
+void
+pdf__add_thumbnail(PDF *p, int im)
+{
+ pdf_image *image;
+
+ pdf_check_handle(p, im, pdc_imagehandle);
+
+ if (pdf_get_thumb_id(p) != PDC_BAD_ID)
+ pdc_error(p->pdc, PDF_E_IMAGE_THUMB, 0, 0, 0, 0);
+
+ image = &p->images[im];
+
+ if (image->strips > 1)
+ pdc_error(p->pdc, PDF_E_IMAGE_THUMB_MULTISTRIP,
+ pdc_errprintf(p->pdc, "%d", im), 0, 0, 0);
+
+ if (image->width > MAX_THUMBNAIL_SIZE || image->height > MAX_THUMBNAIL_SIZE)
+ pdc_error(p->pdc, PDF_E_IMAGE_THUMB_SIZE,
+ pdc_errprintf(p->pdc, "%d", im),
+ pdc_errprintf(p->pdc, "%d", MAX_THUMBNAIL_SIZE), 0, 0);
+
+ if (image->colorspace != (int) DeviceGray &&
+ image->colorspace != (int) DeviceRGB &&
+ image->colorspace != (int) Indexed)
+ pdc_error(p->pdc, PDF_E_IMAGE_THUMB_CS,
+ pdc_errprintf(p->pdc, "%d", im), 0, 0, 0);
+
+ /* Add the image to the thumbnail key of the current page. */
+ pdf_set_thumb_id(p, p->xobjects[image->no].obj_id);
+}