summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvipdf-x/xsrc/pdfximage.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvipdf-x/xsrc/pdfximage.c')
-rw-r--r--Build/source/texk/dvipdf-x/xsrc/pdfximage.c924
1 files changed, 924 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdf-x/xsrc/pdfximage.c b/Build/source/texk/dvipdf-x/xsrc/pdfximage.c
new file mode 100644
index 00000000000..f16829f18ba
--- /dev/null
+++ b/Build/source/texk/dvipdf-x/xsrc/pdfximage.c
@@ -0,0 +1,924 @@
+/*
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2007-2012 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team.
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "system.h"
+#include "error.h"
+#include "mem.h"
+
+#include "dpxfile.h"
+
+#include "pdfobj.h"
+
+#include "pdfdoc.h"
+#include "pdfdev.h"
+#include "pdfdraw.h"
+
+#include "epdf.h"
+#include "mpost.h"
+#include "pngimage.h"
+#include "jpegimage.h"
+#include "bmpimage.h"
+
+#include "pdfximage.h"
+
+/* From psimage.h */
+static int check_for_ps (FILE *fp);
+static int ps_include_page (pdf_ximage *ximage, const char *file_name);
+
+
+#define IMAGE_TYPE_UNKNOWN -1
+#define IMAGE_TYPE_PDF 0
+#define IMAGE_TYPE_JPEG 1
+#define IMAGE_TYPE_PNG 2
+#define IMAGE_TYPE_MPS 4
+#define IMAGE_TYPE_EPS 5
+#define IMAGE_TYPE_BMP 6
+
+
+struct attr_
+{
+ long width, height;
+ double xdensity, ydensity;
+ pdf_rect bbox;
+};
+
+struct pdf_ximage_
+{
+ char *ident;
+ char res_name[16];
+ long page_no, page_count;
+
+ int subtype;
+
+ struct attr_ attr;
+
+ char *filename;
+ pdf_obj *reference;
+ pdf_obj *resource;
+ pdf_obj *attr_dict;
+
+ char tempfile;
+};
+
+
+/* verbose, verbose, verbose... */
+struct opt_
+{
+ int verbose;
+ char *cmdtmpl;
+};
+
+static struct opt_ _opts = {
+ 0, NULL
+};
+
+void pdf_ximage_set_verbose (void) { _opts.verbose++; }
+
+
+struct ic_
+{
+ int count, capacity;
+ pdf_ximage *ximages;
+};
+
+static struct ic_ _ic = {
+ 0, 0, NULL
+};
+
+static void
+pdf_init_ximage_struct (pdf_ximage *I, const char *ident, const char *filename, pdf_obj *dict)
+{
+ if (ident) {
+ I->ident = NEW(strlen(ident)+1, char);
+ strcpy(I->ident, ident);
+ } else
+ I ->ident = NULL;
+ I->page_no = I->page_count = 0;
+ if (filename) {
+ I->filename = NEW(strlen(filename)+1, char);
+ strcpy(I->filename, filename);
+ } else
+ I->filename = NULL;
+ I->subtype = -1;
+ memset(I->res_name, 0, 16);
+ I->reference = NULL;
+ I->resource = NULL;
+ I->attr_dict = dict;
+
+ I->attr.width = I->attr.height = 0;
+ I->attr.xdensity = I->attr.ydensity = 1.0;
+ I->attr.bbox.llx = I->attr.bbox.lly = 0;
+ I->attr.bbox.urx = I->attr.bbox.ury = 0;
+
+ I->tempfile = 0;
+}
+
+static void
+pdf_set_ximage_tempfile (pdf_ximage *I, const char *filename)
+{
+ if (I->filename)
+ RELEASE(I->filename);
+ I->filename = NEW(strlen(filename)+1, char);
+ strcpy(I->filename, filename);
+ I->tempfile = 1;
+}
+
+static void
+pdf_clean_ximage_struct (pdf_ximage *I)
+{
+ if (I->ident)
+ RELEASE(I->ident);
+ if (I->filename)
+ RELEASE(I->filename);
+ if (I->reference)
+ pdf_release_obj(I->reference);
+ if (I->resource)
+ pdf_release_obj(I->resource);
+ if (I->attr_dict)
+ pdf_release_obj(I->attr_dict);
+ pdf_init_ximage_struct(I, NULL, NULL, NULL);
+}
+
+
+void
+pdf_init_images (void)
+{
+ struct ic_ *ic = &_ic;
+ ic->count = 0;
+ ic->capacity = 0;
+ ic->ximages = NULL;
+}
+
+void
+pdf_close_images (void)
+{
+ struct ic_ *ic = &_ic;
+ if (ic->ximages) {
+ int i;
+ for (i = 0; i < ic->count; i++) {
+ pdf_ximage *I = ic->ximages+i;
+ if (I->tempfile) {
+ /*
+ * It is important to remove temporary files at the end because
+ * we cache file names. Since we use mkstemp to create them, we
+ * might get the same file name again if delete the first file.
+ * (This happens on NetBSD, reported by Jukka Salmi.)
+ * We also use this to convert a PS file only once if multiple
+ * pages are imported from that file.
+ */
+ if (_opts.verbose > 1 && keep_cache != 1)
+ MESG("pdf_image>> deleting temporary file \"%s\"\n", I->filename);
+ dpx_delete_temp_file(I->filename, false); /* temporary filename freed here */
+ I->filename = NULL;
+ }
+ pdf_clean_ximage_struct(I);
+ }
+ RELEASE(ic->ximages);
+ ic->ximages = NULL;
+ ic->count = ic->capacity = 0;
+ }
+
+ if (_opts.cmdtmpl)
+ RELEASE(_opts.cmdtmpl);
+ _opts.cmdtmpl = NULL;
+}
+
+static int
+source_image_type (FILE *fp)
+{
+ int format = IMAGE_TYPE_UNKNOWN;
+
+ rewind(fp);
+ /*
+ * Make sure we check for PS *after* checking for MP since
+ * MP is a special case of PS.
+ */
+ if (check_for_jpeg(fp))
+ {
+ format = IMAGE_TYPE_JPEG;
+ }
+#ifdef HAVE_LIBPNG
+ else if (check_for_png(fp))
+ {
+ format = IMAGE_TYPE_PNG;
+ }
+#endif
+ else if (check_for_bmp(fp))
+ {
+ format = IMAGE_TYPE_BMP;
+ } else if (check_for_pdf(fp)) {
+ format = IMAGE_TYPE_PDF;
+ } else if (check_for_mp(fp)) {
+ format = IMAGE_TYPE_MPS;
+ } else if (check_for_ps(fp)) {
+ format = IMAGE_TYPE_EPS;
+ } else {
+ format = IMAGE_TYPE_UNKNOWN;
+ }
+ rewind(fp);
+
+ return format;
+}
+
+static int
+load_image (const char *ident, const char *fullname, int format, FILE *fp,
+ long page_no, pdf_obj *dict)
+{
+ struct ic_ *ic = &_ic;
+ int id = -1; /* ret */
+ pdf_ximage *I;
+
+ id = ic->count;
+ if (ic->count >= ic->capacity) {
+ ic->capacity += 16;
+ ic->ximages = RENEW(ic->ximages, ic->capacity, pdf_ximage);
+ }
+
+ I = &ic->ximages[id];
+ pdf_init_ximage_struct(I, ident, ident, dict);
+ pdf_ximage_set_page(I, page_no, 0);
+
+ switch (format) {
+ case IMAGE_TYPE_JPEG:
+ if (_opts.verbose)
+ MESG("[JPEG]");
+ if (jpeg_include_image(I, fp) < 0)
+ goto error;
+ I->subtype = PDF_XOBJECT_TYPE_IMAGE;
+ break;
+#ifdef HAVE_LIBPNG
+ case IMAGE_TYPE_PNG:
+ if (_opts.verbose)
+ MESG("[PNG]");
+ if (png_include_image(I, fp) < 0)
+ goto error;
+ I->subtype = PDF_XOBJECT_TYPE_IMAGE;
+ break;
+#endif
+ case IMAGE_TYPE_BMP:
+ if (_opts.verbose)
+ MESG("[BMP]");
+ if (bmp_include_image(I, fp) < 0)
+ goto error;
+ I->subtype = PDF_XOBJECT_TYPE_IMAGE;
+ break;
+ case IMAGE_TYPE_PDF:
+ if (_opts.verbose)
+ MESG("[PDF]");
+ if (pdf_include_page(I, fp) < 0)
+ goto error;
+ if (_opts.verbose)
+ MESG(",Page:%ld", I->page_no);
+ I->subtype = PDF_XOBJECT_TYPE_FORM;
+ break;
+ // case IMAGE_TYPE_EPS:
+ default:
+ if (_opts.verbose)
+ MESG(format == IMAGE_TYPE_EPS ? "[PS]" : "[UNKNOWN]");
+ if (ps_include_page(I, fullname) < 0)
+ goto error;
+ if (_opts.verbose)
+ MESG(",Page:%ld", I->page_no);
+ I->subtype = PDF_XOBJECT_TYPE_FORM;
+ }
+
+ switch (I->subtype) {
+ case PDF_XOBJECT_TYPE_IMAGE:
+ sprintf(I->res_name, "Im%d", id);
+ break;
+ case PDF_XOBJECT_TYPE_FORM:
+ sprintf(I->res_name, "Fm%d", id);
+ break;
+ default:
+ ERROR("Unknown XObject subtype: %d", I->subtype);
+ goto error;
+ }
+
+ ic->count++;
+
+ return id;
+
+ error:
+ pdf_clean_ximage_struct(I);
+ return -1;
+}
+
+
+#define dpx_find_file(n,d,s) (kpse_find_pict((n)))
+#define dpx_fopen(n,m) (MFOPEN((n),(m)))
+#define dpx_fclose(f) (MFCLOSE((f)))
+
+int
+pdf_ximage_findresource (const char *ident, long page_no, pdf_obj *dict)
+{
+ struct ic_ *ic = &_ic;
+ int id = -1;
+ pdf_ximage *I;
+ char *fullname;
+ int format;
+ FILE *fp;
+
+ for (id = 0; id < ic->count; id++) {
+ I = &ic->ximages[id];
+ if (I->ident && !strcmp(ident, I->ident) &&
+ I->page_no == page_no + (page_no < 0 ? I->page_count+1 : 0) &&
+ I->attr_dict == dict) {
+ return id;
+ }
+ }
+
+ /* try loading image */
+ fullname = dpx_find_file(ident, "_pic_", "");
+ if (!fullname) {
+ WARN("Error locating image file \"%s\"", ident);
+ return -1;
+ }
+
+ fp = dpx_fopen(fullname, FOPEN_RBIN_MODE);
+ if (!fp) {
+ WARN("Error opening image file \"%s\"", fullname);
+ RELEASE(fullname);
+ return -1;
+ }
+ if (_opts.verbose) {
+ MESG("(Image:%s", ident);
+ if (_opts.verbose > 1)
+ MESG("[%s]", fullname);
+ }
+
+ format = source_image_type(fp);
+ switch (format) {
+ case IMAGE_TYPE_MPS:
+ if (_opts.verbose)
+ MESG("[MPS]");
+ id = mps_include_page(ident, fp);
+ if (id < 0) {
+ WARN("Try again with the distiller.");
+ format = IMAGE_TYPE_EPS;
+ rewind(fp);
+ } else
+ break;
+ default:
+ id = load_image(ident, fullname, format, fp, page_no, dict);
+ break;
+ }
+ dpx_fclose(fp);
+
+ RELEASE(fullname);
+
+ if (_opts.verbose)
+ MESG(")");
+
+ if (id < 0)
+ WARN("pdf: image inclusion failed for \"%s\".", ident);
+
+ return id;
+}
+
+/* Reference: PDF Reference 1.5 v6, pp.321--322
+ *
+ * TABLE 4.42 Additional entries specific to a type 1 form dictionary
+ *
+ * BBox rectangle (Required) An array of four numbers in the form coordinate
+ * system, giving the coordinates of the left, bottom, right,
+ * and top edges, respectively, of the form XObject's bounding
+ * box. These boundaries are used to clip the form XObject and
+ * to determine its size for caching.
+ *
+ * Matrix array (Optional) An array of six numbers specifying the form
+ * matrix, which maps form space into user space.
+ * Default value: the identity matrix [1 0 0 1 0 0].
+ */
+void
+pdf_ximage_init_form_info (xform_info *info)
+{
+ info->flags = 0;
+ info->bbox.llx = 0;
+ info->bbox.lly = 0;
+ info->bbox.urx = 0;
+ info->bbox.ury = 0;
+ info->matrix.a = 1.0;
+ info->matrix.b = 0.0;
+ info->matrix.c = 0.0;
+ info->matrix.d = 1.0;
+ info->matrix.e = 0.0;
+ info->matrix.f = 0.0;
+}
+
+/* Reference: PDF Reference 1.5 v6, pp.303--306
+ *
+ * TABLE 4.42 Additional entries specific to an image dictionary
+ *
+ * Width integer (Required) The width of the image, in samples.
+ *
+ * Height integer (Required) The height of the image, in samples.
+ *
+ * ColorSpace name or array
+ * (Required for images, except those that use the JPXDecode
+ * filter; not allowed for image masks) The color space in
+ * which image samples are specified. This may be any type
+ * of color space except Patter.
+ *
+ * If the image uses the JPXDecode filter, this entry is
+ * optional.
+ *
+ * BitsPerComponent integer
+ * (Required except for image masks and images that use the
+ * JPXDecode filter) The number of bits used to represent
+ * each color component. Only a single value may be specified;
+ * the number of bits is the same for all color components.
+ * Valid values are 1,2,4,8, and (in PDF1.5) 16. If ImageMask
+ * is true, this entry is optional, and if speficified, its
+ * value must be 1.
+ *
+ * If the image stream uses the JPXDecode filter, this entry
+ * is optional and ignored if present. The bit depth is
+ * determined in the process of decoding the JPEG2000 image.
+ */
+void
+pdf_ximage_init_image_info (ximage_info *info)
+{
+ info->flags = 0;
+ info->width = 0;
+ info->height = 0;
+ info->bits_per_component = 0;
+ info->num_components = 0;
+ info->min_dpi = 0;
+ info->xdensity = info->ydensity = 1.0;
+}
+
+char *
+pdf_ximage_get_ident (pdf_ximage *I)
+{
+ return I->ident;
+}
+
+void
+pdf_ximage_set_image (pdf_ximage *I, void *image_info, pdf_obj *resource)
+{
+ pdf_obj *dict;
+ ximage_info *info = image_info;
+
+ if (!PDF_OBJ_STREAMTYPE(resource))
+ ERROR("Image XObject must be of stream type.");
+
+ I->subtype = PDF_XOBJECT_TYPE_IMAGE;
+
+ I->attr.width = info->width; /* The width of the image, in samples */
+ I->attr.height = info->height; /* The height of the image, in samples */
+ I->attr.xdensity = info->xdensity;
+ I->attr.ydensity = info->ydensity;
+
+ I->reference = pdf_ref_obj(resource);
+
+ dict = pdf_stream_dict(resource);
+ pdf_add_dict(dict, pdf_new_name("Type"), pdf_new_name("XObject"));
+ pdf_add_dict(dict, pdf_new_name("Subtype"), pdf_new_name("Image"));
+ pdf_add_dict(dict, pdf_new_name("Width"), pdf_new_number(info->width));
+ pdf_add_dict(dict, pdf_new_name("Height"), pdf_new_number(info->height));
+ pdf_add_dict(dict, pdf_new_name("BitsPerComponent"),
+ pdf_new_number(info->bits_per_component));
+ if (I->attr_dict)
+ pdf_merge_dict(dict, I->attr_dict);
+
+ pdf_release_obj(resource); /* Caller don't know we are using reference. */
+ I->resource = NULL;
+}
+
+void
+pdf_ximage_set_form (pdf_ximage *I, void *form_info, pdf_obj *resource)
+{
+ xform_info *info = form_info;
+
+ I->subtype = PDF_XOBJECT_TYPE_FORM;
+
+ I->attr.bbox.llx = info->bbox.llx;
+ I->attr.bbox.lly = info->bbox.lly;
+ I->attr.bbox.urx = info->bbox.urx;
+ I->attr.bbox.ury = info->bbox.ury;
+
+ I->reference = pdf_ref_obj(resource);
+
+ pdf_release_obj(resource); /* Caller don't know we are using reference. */
+ I->resource = NULL;
+}
+
+long
+pdf_ximage_get_page (pdf_ximage *I)
+{
+ return I->page_no;
+}
+
+void
+pdf_ximage_set_page (pdf_ximage *I, long page_no, long page_count)
+{
+ I->page_no = page_no;
+ I->page_count = page_count;
+}
+
+
+#define CHECK_ID(c,n) do {\
+ if ((n) < 0 || (n) >= (c)->count) {\
+ ERROR("Invalid XObject ID: %d", (n));\
+ }\
+} while (0)
+#define GET_IMAGE(c,n) (&((c)->ximages[(n)]))
+
+pdf_obj *
+pdf_ximage_get_reference (int id)
+{
+ struct ic_ *ic = &_ic;
+ pdf_ximage *I;
+
+ CHECK_ID(ic, id);
+
+ I = GET_IMAGE(ic, id);
+ if (!I->reference)
+ I->reference = pdf_ref_obj(I->resource);
+
+ return pdf_link_obj(I->reference);
+}
+
+/* called from pdfdoc.c only for late binding */
+int
+pdf_ximage_defineresource (const char *ident,
+ int subtype, void *info, pdf_obj *resource)
+{
+ struct ic_ *ic = &_ic;
+ int id;
+ pdf_ximage *I;
+
+ id = ic->count;
+ if (ic->count >= ic->capacity) {
+ ic->capacity += 16;
+ ic->ximages = RENEW(ic->ximages, ic->capacity, pdf_ximage);
+ }
+
+ I = &ic->ximages[id];
+
+ pdf_init_ximage_struct(I, ident, NULL, NULL);
+
+ switch (subtype) {
+ case PDF_XOBJECT_TYPE_IMAGE:
+ pdf_ximage_set_image(I, info, resource);
+ sprintf(I->res_name, "Im%d", id);
+ break;
+ case PDF_XOBJECT_TYPE_FORM:
+ pdf_ximage_set_form (I, info, resource);
+ sprintf(I->res_name, "Fm%d", id);
+ break;
+ default:
+ ERROR("Unknown XObject subtype: %d", subtype);
+ }
+ ic->count++;
+
+ return id;
+}
+
+
+char *
+pdf_ximage_get_resname (int id)
+{
+ struct ic_ *ic = &_ic;
+ pdf_ximage *I;
+
+ CHECK_ID(ic, id);
+
+ I = GET_IMAGE(ic, id);
+
+ return I->res_name;
+}
+
+
+/* depth...
+ * Dvipdfm treat "depth" as "yoffset" for pdf:image and pdf:uxobj
+ * not as vertical dimension of scaled image. (And there are bugs.)
+ * This part contains incompatibile behaviour than dvipdfm!
+ */
+#define EBB_DPI 72
+
+static void
+scale_to_fit_I (pdf_tmatrix *T,
+ transform_info *p,
+ pdf_ximage *I)
+{
+ double s_x, s_y, d_x, d_y;
+ double wd0, ht0, dp, xscale, yscale;
+
+ if (p->flags & INFO_HAS_USER_BBOX) {
+ wd0 = p->bbox.urx - p->bbox.llx;
+ ht0 = p->bbox.ury - p->bbox.lly;
+ xscale = I->attr.width * I->attr.xdensity / wd0;
+ yscale = I->attr.height * I->attr.ydensity / ht0;
+ d_x = -p->bbox.llx / wd0;
+ d_y = -p->bbox.lly / ht0;
+ } else {
+ wd0 = I->attr.width * I->attr.xdensity;
+ ht0 = I->attr.height * I->attr.ydensity;
+ xscale = yscale = 1.0;
+ d_x = 0.0;
+ d_y = 0.0;
+ }
+
+ if (wd0 == 0.0) {
+ WARN("Image width=0.0!");
+ wd0 = 1.0;
+ }
+ if (ht0 == 0.0) {
+ WARN("Image height=0.0!");
+ ht0 = 1.0;
+ }
+
+ if ( (p->flags & INFO_HAS_WIDTH ) &&
+ (p->flags & INFO_HAS_HEIGHT) ) {
+ s_x = p->width * xscale;
+ s_y = (p->height + p->depth) * yscale;
+ dp = p->depth * yscale;
+ } else if ( p->flags & INFO_HAS_WIDTH ) {
+ s_x = p->width * xscale;
+ s_y = s_x * ((double)I->attr.height / I->attr.width);
+ dp = 0.0;
+ } else if ( p->flags & INFO_HAS_HEIGHT) {
+ s_y = (p->height + p->depth) * yscale;
+ s_x = s_y * ((double)I->attr.width / I->attr.height);
+ dp = p->depth * yscale;
+ } else {
+ s_x = wd0;
+ s_y = ht0;
+ dp = 0.0;
+ }
+ T->a = s_x; T->c = 0.0;
+ T->b = 0.0; T->d = s_y;
+ T->e = d_x * s_x / xscale; T->f = d_y * s_y / yscale - dp;
+
+ return;
+}
+
+
+static void
+scale_to_fit_F (pdf_tmatrix *T,
+ transform_info *p,
+ pdf_ximage *I)
+{
+ double s_x, s_y, d_x, d_y;
+ double wd0, ht0, dp;
+
+ if (p->flags & INFO_HAS_USER_BBOX) {
+ wd0 = p->bbox.urx - p->bbox.llx;
+ ht0 = p->bbox.ury - p->bbox.lly;
+ d_x = -p->bbox.llx;
+ d_y = -p->bbox.lly;
+ } else {
+ wd0 = I->attr.bbox.urx - I->attr.bbox.llx;
+ ht0 = I->attr.bbox.ury - I->attr.bbox.lly;
+ d_x = 0.0;
+ d_y = 0.0;
+ }
+
+ if (wd0 == 0.0) {
+ WARN("Image width=0.0!");
+ wd0 = 1.0;
+ }
+ if (ht0 == 0.0) {
+ WARN("Image height=0.0!");
+ ht0 = 1.0;
+ }
+
+ if ( (p->flags & INFO_HAS_WIDTH ) &&
+ (p->flags & INFO_HAS_HEIGHT) ) {
+ s_x = p->width / wd0;
+ s_y = (p->height + p->depth) / ht0;
+ dp = p->depth;
+ } else if ( p->flags & INFO_HAS_WIDTH ) {
+ s_x = p->width / wd0;
+ s_y = s_x;
+ dp = 0.0;
+ } else if ( p->flags & INFO_HAS_HEIGHT) {
+ s_y = (p->height + p->depth) / ht0;
+ s_x = s_y;
+ dp = p->depth;
+ } else {
+ s_x = s_y = 1.0;
+ dp = 0.0;
+ }
+
+ T->a = s_x; T->c = 0.0;
+ T->b = 0.0; T->d = s_y;
+ T->e = s_x * d_x; T->f = s_y * d_y - dp;
+
+ return;
+}
+
+
+/* called from pdfdev.c and spc_html.c */
+int
+pdf_ximage_scale_image (int id,
+ pdf_tmatrix *M, /* return value for trans matrix */
+ pdf_rect *r, /* return value for clipping */
+ transform_info *p /* argument from specials */
+ )
+{
+ struct ic_ *ic = &_ic;
+ pdf_ximage *I;
+
+ CHECK_ID(ic, id);
+
+ I = GET_IMAGE(ic, id);
+
+ pdf_setmatrix(M, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+
+ switch (I->subtype) {
+ /* Reference: PDF Reference 1.5 v6, p.302
+ *
+ * An image can be placed on the output page in any desired position,
+ * orientation, and size by using the cm operator to modify the current
+ * transformation matrix (CTM) so as to map the unit square of user space
+ * to the rectangle or parallelogram in which the image is to be painted.
+ *
+ * There is neither BBox nor Matrix key in the image XObject.
+ * Everything must be controlled by the cm operator.
+ *
+ * The argument [p] contains the user-defined bounding box, the scailing
+ * factor of which is bp as EPS and PDF. On the other hand, I->attr
+ * contains the (sampling) width and the (sampling) height of the image.
+ *
+ * There is no problem if a bitmap image has density information.
+ * Otherwise, DVIPDFM's ebb generates bounding box as 100px = 72bp = 1in.
+ * In this case, screen captured images look bad. Moreover, DVIPDFM's ebb
+ * ignores all density information and use just 100px = 72bp = 1in.
+ *
+ * On the other hand, pdfTeX uses 100px = 100bp to get a better quality
+ * for screen captured images.
+ *
+ * DVIPDFMx's xbb generates bounding box as 100px = 100bp in the same
+ * way as pdfTeX. Furthermore, it takes care of density information too.
+ */
+ case PDF_XOBJECT_TYPE_IMAGE:
+ scale_to_fit_I(M, p, I);
+ if (p->flags & INFO_HAS_USER_BBOX) {
+ r->llx = p->bbox.llx / (I->attr.width * I->attr.xdensity);
+ r->lly = p->bbox.lly / (I->attr.height * I->attr.ydensity);
+ r->urx = p->bbox.urx / (I->attr.width * I->attr.xdensity);
+ r->ury = p->bbox.ury / (I->attr.height * I->attr.ydensity);
+ } else {
+ r->llx = 0.0;
+ r->lly = 0.0;
+ r->urx = 1.0;
+ r->ury = 1.0;
+ }
+ break;
+ /* User-defined transformation and clipping are controlled by
+ * the cm operator and W operator, explicitly */
+ case PDF_XOBJECT_TYPE_FORM:
+ scale_to_fit_F(M, p, I);
+ if (p->flags & INFO_HAS_USER_BBOX) {
+ r->llx = p->bbox.llx;
+ r->lly = p->bbox.lly;
+ r->urx = p->bbox.urx;
+ r->ury = p->bbox.ury;
+ } else { /* I->attr.bbox from the image bounding box */
+ r->llx = I->attr.bbox.llx;
+ r->lly = I->attr.bbox.lly;
+ r->urx = I->attr.bbox.urx;
+ r->ury = I->attr.bbox.ury;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+
+/* Migrated from psimage.c */
+
+void set_distiller_template (char *s)
+{
+ if (_opts.cmdtmpl)
+ RELEASE(_opts.cmdtmpl);
+ if (!s || *s == '\0')
+ _opts.cmdtmpl = NULL;
+ else {
+ _opts.cmdtmpl = NEW(strlen(s) + 1, char);
+ strcpy(_opts.cmdtmpl, s);
+ }
+ return;
+}
+
+char *get_distiller_template (void)
+{
+ return _opts.cmdtmpl;
+}
+
+static int
+ps_include_page (pdf_ximage *ximage, const char *filename)
+{
+ char *distiller_template = _opts.cmdtmpl;
+ char *temp;
+ FILE *fp;
+ int error = 0;
+ struct stat stat_o, stat_t;
+
+ if (!distiller_template) {
+ WARN("No image converter available for converting file \"%s\" to PDF format.", filename);
+ WARN(">> Please check if you have 'D' option in config file.");
+ return -1;
+ }
+
+ temp = dpx_create_fix_temp_file(filename);
+ if (!temp) {
+ WARN("Failed to create temporary file for image conversion: %s", filename);
+ return -1;
+ }
+
+#ifdef MIKTEX
+ {
+ char *p;
+ for (p = (char *)filename; *p; p++) {
+ if (*p == '\\') *p = '/';
+ }
+ for (p = (char *)temp; *p; p++) {
+ if (*p == '\\') *p = '/';
+ }
+ }
+#endif
+ if (keep_cache != -1 && stat(temp, &stat_t)==0 && stat(filename, &stat_o)==0
+ && stat_t.st_mtime > stat_o.st_mtime) {
+ /* cache exist */
+ /*printf("\nLast file modification: %s", ctime(&stat_o.st_mtime));
+ printf("Last file modification: %s", ctime(&stat_t.st_mtime));*/
+ ;
+ } else {
+ if (_opts.verbose > 1) {
+ MESG("\n");
+ MESG("pdf_image>> Converting file \"%s\" --> \"%s\" via:\n", filename, temp);
+ MESG("pdf_image>> %s\n", distiller_template);
+ MESG("pdf_image>> ...");
+ }
+ error = dpx_file_apply_filter(distiller_template, filename, temp,
+ (unsigned char) pdf_get_version());
+ if (error) {
+ WARN("Image format conversion for \"%s\" failed...", filename);
+ dpx_delete_temp_file(temp, true);
+ return error;
+ }
+ }
+
+ fp = MFOPEN(temp, FOPEN_RBIN_MODE);
+ if (!fp) {
+ WARN("Could not open conversion result \"%s\" for image \"%s\". Why?", temp, filename);
+ dpx_delete_temp_file(temp, true);
+ return -1;
+ }
+ pdf_set_ximage_tempfile(ximage, temp);
+// error = pdf_include_page(ximage, fp, 0, pdfbox_crop);
+ error = pdf_include_page(ximage, fp);
+ MFCLOSE(fp);
+
+ /* See pdf_close_images for why we cannot delete temporary files here. */
+
+ RELEASE(temp);
+
+ if (error) {
+ WARN("Failed to include image file \"%s\"", filename);
+ WARN(">> Please check if");
+ WARN(">> %s", distiller_template);
+ WARN(">> %%o = output filename, %%i = input filename, %%b = input filename without suffix");
+ WARN(">> can really convert \"%s\" to PDF format image.", filename);
+ }
+
+ return error;
+}
+
+static int check_for_ps (FILE *image_file)
+{
+ rewind (image_file);
+ mfgets (work_buffer, WORK_BUFFER_SIZE, image_file);
+ if (!strncmp (work_buffer, "%!", 2))
+ return 1;
+ return 0;
+}