Back to index

texmacs  1.0.7.15
pdfximage.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/pdfximage.c,v 1.27 2010/05/29 20:56:42 matthias Exp $
00002     
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2007 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014     
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019     
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023 */
00024 
00025 #if HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028 
00029 #include <string.h>
00030 
00031 #include "system.h"
00032 #include "error.h"
00033 #include "mem.h"
00034 
00035 #include "dpxfile.h"
00036 
00037 #include "pdfobj.h"
00038 
00039 #include "pdfdoc.h"
00040 #include "pdfdev.h"
00041 #include "pdfdraw.h"
00042 
00043 #include "epdf.h"
00044 #include "pngimage.h"
00045 #include "jpegimage.h"
00046 #include "bmpimage.h"
00047 
00048 #include "pdfximage.h"
00049 
00050 /* From psimage.h */
00051 static int  check_for_ps    (FILE *fp);
00052 static int  ps_include_page (pdf_ximage *ximage);
00053 
00054 
00055 #define IMAGE_TYPE_UNKNOWN -1
00056 #define IMAGE_TYPE_PDF      0
00057 #define IMAGE_TYPE_JPEG     1
00058 #define IMAGE_TYPE_PNG      2
00059 #define IMAGE_TYPE_MPS      4
00060 #define IMAGE_TYPE_EPS      5
00061 #define IMAGE_TYPE_BMP      6
00062 
00063 
00064 struct attr_
00065 {
00066   long     width, height;
00067   double   xdensity, ydensity;
00068   pdf_rect bbox;
00069 };
00070 
00071 struct pdf_ximage_
00072 {
00073   char        *ident;
00074   char         res_name[16];
00075   long         page_no;
00076 
00077   int          subtype;
00078 
00079   struct attr_ attr;
00080 
00081   char        *filename;
00082   pdf_obj     *reference;
00083   pdf_obj     *resource;
00084   pdf_obj     *attr_dict;
00085 
00086   char         tempfile;
00087 };
00088 
00089 
00090 /* verbose, verbose, verbose... */
00091 struct opt_
00092 {
00093   int    verbose;
00094   char  *cmdtmpl;
00095 };
00096 
00097 static struct opt_ _opts = {
00098   0, NULL
00099 };
00100 
00101 void pdf_ximage_set_verbose (void) { _opts.verbose++; }
00102 
00103 
00104 struct ic_
00105 {
00106   int         count, capacity;
00107   pdf_ximage *ximages;
00108 };
00109 
00110 static struct ic_  _ic = {
00111   0, 0, NULL
00112 };
00113 
00114 static void
00115 pdf_init_ximage_struct (pdf_ximage *I,
00116                      const char *ident, const char *filename,
00117                      long page_no, pdf_obj *dict)
00118 {
00119   if (ident) {
00120     I->ident = NEW(strlen(ident)+1, char);
00121     strcpy(I->ident, ident);
00122   } else
00123     I ->ident = NULL;
00124   I->page_no  = page_no;
00125   if (filename) {
00126     I->filename = NEW(strlen(filename)+1, char);
00127     strcpy(I->filename, filename);
00128   } else
00129     I->filename = NULL;
00130   I->subtype  = -1;
00131   memset(I->res_name, 0, 16);
00132   I->reference = NULL;
00133   I->resource  = NULL;
00134   I->attr_dict = dict;
00135 
00136   I->attr.width = I->attr.height = 0;
00137   I->attr.xdensity = I->attr.ydensity = 1.0;
00138   I->attr.bbox.llx = I->attr.bbox.lly = 0;
00139   I->attr.bbox.urx = I->attr.bbox.ury = 0;
00140 
00141   I->tempfile = 0;
00142 }
00143 
00144 static void
00145 pdf_set_ximage_tempfile (pdf_ximage *I, const char *filename)
00146 {
00147   if (I->filename)
00148     RELEASE(I->filename);
00149   I->filename = NEW(strlen(filename)+1, char);
00150   strcpy(I->filename, filename);
00151   I->tempfile = 1;
00152 }
00153 
00154 static void
00155 pdf_clean_ximage_struct (pdf_ximage *I)
00156 {
00157   if (I->ident)
00158     RELEASE(I->ident);
00159   if (I->filename)
00160     RELEASE(I->filename);
00161   if (I->reference)
00162     pdf_release_obj(I->reference);
00163   if (I->resource)
00164     pdf_release_obj(I->resource);
00165   if (I->attr_dict)
00166     pdf_release_obj(I->attr_dict);
00167   pdf_init_ximage_struct(I, NULL, NULL, 0, NULL);
00168 }
00169 
00170 
00171 void
00172 pdf_init_images (void)
00173 {
00174   struct ic_ *ic = &_ic;
00175   ic->count    = 0;
00176   ic->capacity = 0;
00177   ic->ximages  = NULL;
00178 }
00179 
00180 void
00181 pdf_close_images (void)
00182 {
00183   struct ic_ *ic = &_ic;
00184   if (ic->ximages) {
00185     int  i;
00186     for (i = 0; i < ic->count; i++) {
00187       pdf_ximage *I = ic->ximages+i;
00188       if (I->tempfile) {
00189        /*
00190         * It is important to remove temporary files at the end because
00191         * we cache file names. Since we use mkstemp to create them, we
00192         * might get the same file name again if delete the first file.
00193         * (This happens on NetBSD, reported by Jukka Salmi.)
00194         * We also use this to convert a PS file only once if multiple
00195         * pages are imported from that file.
00196         */
00197        if (_opts.verbose > 1)
00198          MESG("pdf_image>> deleting temporary file \"%s\"\n", I->filename);
00199        dpx_delete_temp_file(I->filename); /* temporary filename freed here */
00200        I->filename = NULL;
00201       }
00202       pdf_clean_ximage_struct(I);
00203     }
00204     RELEASE(ic->ximages);
00205     ic->ximages = NULL;
00206     ic->count = ic->capacity = 0;
00207   }
00208 
00209   if (_opts.cmdtmpl)
00210     RELEASE(_opts.cmdtmpl);
00211   _opts.cmdtmpl = NULL;
00212 }
00213 
00214 
00215 static int
00216 source_image_type (FILE *fp)
00217 {
00218   int  format = IMAGE_TYPE_UNKNOWN;
00219 
00220   rewind(fp);
00221   /*
00222    * Make sure we check for PS *after* checking for MP since
00223    * MP is a special case of PS.
00224    */
00225   if (check_for_jpeg(fp))
00226   {
00227     format = IMAGE_TYPE_JPEG;
00228   }
00229 #ifdef  HAVE_LIBPNG
00230   else if (check_for_png(fp))
00231   {
00232     format = IMAGE_TYPE_PNG;
00233   }
00234 #endif
00235   else if (check_for_bmp(fp))
00236   {
00237     format = IMAGE_TYPE_BMP;
00238   } else if (check_for_pdf(fp)) {
00239     format = IMAGE_TYPE_PDF;
00240 #if 0
00241   } else if (check_for_mp(fp)) {
00242     format = IMAGE_TYPE_MPS;
00243 #endif
00244   } else if (check_for_ps(fp)) {
00245     format = IMAGE_TYPE_EPS;
00246   } else {
00247     format = IMAGE_TYPE_UNKNOWN;
00248   }
00249   rewind(fp);
00250 
00251   return  format;
00252 }
00253 
00254 static int
00255 load_image (const char *ident, const char *fullname, int format, FILE  *fp,
00256             long page_no, pdf_obj *dict)
00257 {
00258   struct ic_ *ic = &_ic;
00259   int         id = -1; /* ret */
00260   pdf_ximage *I;
00261 
00262   id = ic->count;
00263   if (ic->count >= ic->capacity) {
00264     ic->capacity += 16;
00265     ic->ximages   = RENEW(ic->ximages, ic->capacity, pdf_ximage);
00266   }
00267 
00268   I  = &ic->ximages[id];
00269   pdf_init_ximage_struct(I, ident, fullname, page_no, dict);
00270 
00271   switch (format) {
00272   case  IMAGE_TYPE_JPEG:
00273     if (_opts.verbose)
00274       MESG("[JPEG]");
00275     if (jpeg_include_image(I, fp) < 0)
00276       goto error;
00277     I->subtype  = PDF_XOBJECT_TYPE_IMAGE;
00278     break;
00279 #ifdef HAVE_LIBPNG
00280   case  IMAGE_TYPE_PNG:
00281     if (_opts.verbose)
00282       MESG("[PNG]");
00283     if (png_include_image(I, fp) < 0)
00284       goto error;
00285     I->subtype  = PDF_XOBJECT_TYPE_IMAGE;
00286     break;
00287 #endif
00288   case  IMAGE_TYPE_BMP:
00289     if (_opts.verbose)
00290       MESG("[BMP]");
00291     if (bmp_include_image(I, fp) < 0)
00292       goto error;
00293     I->subtype  = PDF_XOBJECT_TYPE_IMAGE;
00294     break;
00295   case  IMAGE_TYPE_PDF:
00296     if (_opts.verbose)
00297       MESG("[PDF]");
00298     {
00299       int result = pdf_include_page(I, fp, fullname);
00300       if (result > 0)
00301        /* PDF version too recent */
00302        result = ps_include_page(I);
00303       if (result < 0)
00304        goto error;
00305     }
00306     if (_opts.verbose)
00307       MESG(",Page:%ld", I->page_no);
00308     I->subtype  = PDF_XOBJECT_TYPE_FORM;
00309     break;
00310   // case  IMAGE_TYPE_EPS:
00311   default:
00312     if (_opts.verbose)
00313       MESG(format == IMAGE_TYPE_EPS ? "[PS]" : "[UNKNOWN]");
00314     if (ps_include_page(I) < 0)
00315       goto error;
00316     if (_opts.verbose)
00317       MESG(",Page:%ld", I->page_no);
00318     I->subtype  = PDF_XOBJECT_TYPE_FORM;
00319   }
00320 
00321   switch (I->subtype) {
00322   case PDF_XOBJECT_TYPE_IMAGE:
00323     sprintf(I->res_name, "Im%d", id);
00324     break;
00325   case PDF_XOBJECT_TYPE_FORM:
00326     sprintf(I->res_name, "Fm%d", id);
00327     break;
00328   default:
00329     ERROR("Unknown XObject subtype: %d", I->subtype);
00330     goto error;
00331   }
00332 
00333   ic->count++;
00334 
00335   return  id;
00336 
00337  error:
00338   pdf_clean_ximage_struct(I);
00339   return -1;
00340 }
00341 
00342 
00343 #define dpx_find_file(n,d,s) (kpse_find_pict((n)))
00344 #define dpx_fopen(n,m) (MFOPEN((n),(m)))
00345 #define dpx_fclose(f)  (MFCLOSE((f)))
00346 
00347 int
00348 pdf_ximage_findresource (const char *ident, long page_no, pdf_obj *dict)
00349 {
00350   struct ic_ *ic = &_ic;
00351   int         id = -1;
00352   pdf_ximage *I;
00353   char       *fullname, *f = NULL;
00354   int         format;
00355   FILE       *fp;
00356 
00357   for (id = 0; id < ic->count; id++) {
00358     I = &ic->ximages[id];
00359     if (I->ident && !strcmp(ident, I->ident)) {
00360       f = I->filename;
00361       if (I->page_no == page_no && I->attr_dict == dict) {
00362        return  id;
00363       }
00364     }
00365   }
00366 
00367   if (f) {
00368     /* we already have converted this file; f is the temporary file name */
00369     fullname = NEW(strlen(f)+1, char);
00370     strcpy(fullname, f);
00371   } else {
00372 #ifdef NOKPSE
00373     /* try loading image */
00374     fullname = dpx_find_file(ident, "_pic_", "");
00375 #else
00376     fullname = NEW(strlen(ident)+1, char);
00377     strcpy(fullname, ident);
00378 #endif
00379     if (!fullname) {
00380       WARN("Error locating image file \"%s\"", ident);
00381       return  -1;
00382     }
00383   }
00384 
00385   fp = dpx_fopen(fullname, FOPEN_RBIN_MODE);
00386   if (!fp) {
00387     WARN("Error opening image file \"%s\"", fullname);
00388     RELEASE(fullname);
00389     return  -1;
00390   }
00391   if (_opts.verbose) {
00392     MESG("(Image:%s", ident);
00393     if (_opts.verbose > 1)
00394       MESG("[%s]", fullname);
00395   }
00396 
00397   format = source_image_type(fp);
00398   switch (format) {
00399 #if 0
00400   case IMAGE_TYPE_MPS:
00401     if (_opts.verbose)
00402       MESG("[MPS]");
00403     id = mps_include_page(ident, fp);
00404     if (id < 0) {
00405       WARN("Try again with the distiller.");
00406       format = IMAGE_TYPE_EPS;
00407       rewind(fp);
00408     } else
00409       break;
00410 #endif
00411   default:
00412     id = load_image(ident, fullname, format, fp, page_no, dict);
00413     break;
00414   }
00415   dpx_fclose(fp);
00416 
00417   RELEASE(fullname);
00418 
00419   if (_opts.verbose)
00420     MESG(")");
00421 
00422   if (id < 0)
00423     WARN("pdf: image inclusion failed for \"%s\".", ident);
00424 
00425   return  id;
00426 }
00427 
00428 /* Reference: PDF Reference 1.5 v6, pp.321--322
00429  *
00430  * TABLE 4.42 Additional entries specific to a type 1 form dictionary
00431  *
00432  * BBox rectangle (Required) An array of four numbers in the form coordinate
00433  *                system, giving the coordinates of the left, bottom, right,
00434  *                and top edges, respectively, of the form XObject's bounding
00435  *                box. These boundaries are used to clip the form XObject and
00436  *                to determine its size for caching.
00437  *
00438  * Matrix array   (Optional) An array of six numbers specifying the form
00439  *                matrix, which maps form space into user space.
00440  *                Default value: the identity matrix [1 0 0 1 0 0].
00441  */
00442 void
00443 pdf_ximage_init_form_info (xform_info *info)
00444 {
00445   info->flags    = 0;
00446   info->bbox.llx = 0;
00447   info->bbox.lly = 0;
00448   info->bbox.urx = 0;
00449   info->bbox.ury = 0;
00450   info->matrix.a = 1.0;
00451   info->matrix.b = 0.0;
00452   info->matrix.c = 0.0;
00453   info->matrix.d = 1.0;
00454   info->matrix.e = 0.0;
00455   info->matrix.f = 0.0;
00456 }
00457 
00458 /* Reference: PDF Reference 1.5 v6, pp.303--306
00459  *
00460  * TABLE 4.42 Additional entries specific to an image dictionary
00461  *
00462  * Width integer  (Required) The width of the image, in samples.
00463  *
00464  * Height integer (Required) The height of the image, in samples.
00465  *
00466  * ColorSpace name or array
00467  *                (Required for images, except those that use the JPXDecode
00468  *                filter; not allowed for image masks) The color space in
00469  *                which image samples are specified. This may be any type
00470  *                of color space except Patter.
00471  *
00472  *                If the image uses the JPXDecode filter, this entry is
00473  *                optional.
00474  *
00475  * BitsPerComponent integer
00476  *                (Required except for image masks and images that use the
00477  *                JPXDecode filter) The number of bits used to represent
00478  *                each color component. Only a single value may be specified;
00479  *                the number of bits is the same for all color components.
00480  *                Valid values are 1,2,4,8, and (in PDF1.5) 16. If ImageMask
00481  *                is true, this entry is optional, and if speficified, its
00482  *                value must be 1.
00483  *
00484  *                If the image stream uses the JPXDecode filter, this entry
00485  *                is optional and ignored if present. The bit depth is
00486  *                determined in the process of decoding the JPEG2000 image.
00487  */
00488 void
00489 pdf_ximage_init_image_info (ximage_info *info)
00490 {
00491   info->flags  = 0;
00492   info->width  = 0;
00493   info->height = 0;
00494   info->bits_per_component = 0;
00495   info->num_components = 0;
00496   info->min_dpi = 0;
00497   info->xdensity = info->ydensity = 1.0;
00498 }
00499 
00500 void
00501 pdf_ximage_set_image (pdf_ximage *I, void *image_info, pdf_obj *resource)
00502 {
00503   pdf_obj     *dict;
00504   ximage_info *info = image_info;
00505 
00506   if (!PDF_OBJ_STREAMTYPE(resource))
00507     ERROR("Image XObject must be of stream type.");
00508 
00509   I->subtype = PDF_XOBJECT_TYPE_IMAGE;
00510 
00511   I->attr.width  = info->width;  /* The width of the image, in samples */
00512   I->attr.height = info->height; /* The height of the image, in samples */
00513   I->attr.xdensity = info->xdensity;
00514   I->attr.ydensity = info->ydensity;
00515 
00516   I->reference = pdf_ref_obj(resource);
00517 
00518   dict = pdf_stream_dict(resource);
00519   pdf_add_dict(dict, pdf_new_name("Type"),    pdf_new_name("XObject"));
00520   pdf_add_dict(dict, pdf_new_name("Subtype"), pdf_new_name("Image"));
00521   pdf_add_dict(dict, pdf_new_name("Width"),   pdf_new_number(info->width));
00522   pdf_add_dict(dict, pdf_new_name("Height"),  pdf_new_number(info->height));
00523   pdf_add_dict(dict, pdf_new_name("BitsPerComponent"),
00524                pdf_new_number(info->bits_per_component));
00525   if (I->attr_dict)
00526     pdf_merge_dict(dict, I->attr_dict);
00527 
00528   pdf_release_obj(resource); /* Caller don't know we are using reference. */
00529   I->resource  = NULL;
00530 }
00531 
00532 void
00533 pdf_ximage_set_form (pdf_ximage *I, void *form_info, pdf_obj *resource)
00534 {
00535   xform_info *info = form_info;
00536 
00537   I->subtype   = PDF_XOBJECT_TYPE_FORM;
00538 
00539   I->attr.bbox.llx = info->bbox.llx;
00540   I->attr.bbox.lly = info->bbox.lly;
00541   I->attr.bbox.urx = info->bbox.urx;
00542   I->attr.bbox.ury = info->bbox.ury;
00543 
00544   I->reference = pdf_ref_obj(resource);
00545 
00546   pdf_release_obj(resource); /* Caller don't know we are using reference. */
00547   I->resource  = NULL;
00548 }
00549 
00550 long
00551 pdf_ximage_get_page (pdf_ximage *I)
00552 {
00553   return I->page_no;
00554 }
00555 
00556 #define CHECK_ID(c,n) do {\
00557   if ((n) < 0 || (n) >= (c)->count) {\
00558     ERROR("Invalid XObject ID: %d", (n));\
00559   }\
00560 } while (0)
00561 #define GET_IMAGE(c,n) (&((c)->ximages[(n)]))
00562 
00563 pdf_obj *
00564 pdf_ximage_get_reference (int id)
00565 {
00566   struct ic_ *ic = &_ic;
00567   pdf_ximage *I;
00568 
00569   CHECK_ID(ic, id);
00570 
00571   I = GET_IMAGE(ic, id);
00572   if (!I->reference)
00573     I->reference = pdf_ref_obj(I->resource);
00574 
00575   return pdf_link_obj(I->reference);
00576 }
00577 
00578 /* called from pdfdoc.c only for late binding */
00579 int
00580 pdf_ximage_defineresource (const char *ident,
00581                         int subtype, void *info, pdf_obj *resource)
00582 {
00583   struct ic_ *ic = &_ic;
00584   int         id;
00585   pdf_ximage *I;
00586 
00587   id = ic->count;
00588   if (ic->count >= ic->capacity) {
00589     ic->capacity += 16;
00590     ic->ximages   = RENEW(ic->ximages, ic->capacity, pdf_ximage);
00591   }
00592 
00593   I = &ic->ximages[id];
00594 
00595   pdf_init_ximage_struct(I, ident, NULL, 0, NULL);
00596 
00597   switch (subtype) {
00598   case PDF_XOBJECT_TYPE_IMAGE:
00599     pdf_ximage_set_image(I, info, resource);
00600     sprintf(I->res_name, "Im%d", id);
00601     break;
00602   case PDF_XOBJECT_TYPE_FORM:
00603     pdf_ximage_set_form (I, info, resource);
00604     sprintf(I->res_name, "Fm%d", id);
00605     break;
00606   default:
00607     ERROR("Unknown XObject subtype: %d", subtype);
00608   }
00609   ic->count++;
00610 
00611   return  id;
00612 }
00613 
00614 
00615 char *
00616 pdf_ximage_get_resname (int id)
00617 {
00618   struct ic_ *ic = &_ic;
00619   pdf_ximage *I;
00620 
00621   CHECK_ID(ic, id);
00622 
00623   I = GET_IMAGE(ic, id);
00624 
00625   return I->res_name;
00626 }
00627 
00628 int
00629 pdf_ximage_get_subtype (int id)
00630 {
00631   struct ic_ *ic = &_ic;
00632   pdf_ximage *I;
00633 
00634   CHECK_ID(ic, id);
00635 
00636   I = GET_IMAGE(ic, id);
00637 
00638   return I->subtype;
00639 }
00640 
00641 void
00642 pdf_ximage_set_attr (int id, long width, long height, double xdensity, double ydensity, double llx, double lly, double urx, double ury)
00643 {
00644   struct ic_ *ic = &_ic;
00645   pdf_ximage *I;
00646 
00647   CHECK_ID(ic, id);
00648 
00649   I = GET_IMAGE(ic, id);
00650   I->attr.width = width;
00651   I->attr.height = height;
00652   I->attr.xdensity = xdensity;
00653   I->attr.ydensity = ydensity;
00654   I->attr.bbox.llx = llx;
00655   I->attr.bbox.lly = lly;
00656   I->attr.bbox.urx = urx;
00657   I->attr.bbox.ury = ury;
00658 }
00659 
00660 /* depth...
00661  * Dvipdfm treat "depth" as "yoffset" for pdf:image and pdf:uxobj
00662  * not as vertical dimension of scaled image. (And there are bugs.)
00663  * This part contains incompatibile behaviour than dvipdfm!
00664  */
00665 #define EBB_DPI 72
00666 
00667 static void
00668 scale_to_fit_I (pdf_tmatrix    *T,
00669                 transform_info *p,
00670                 pdf_ximage     *I)
00671 {
00672   double  s_x, s_y, d_x, d_y;
00673   double  wd0, ht0, dp, xscale, yscale;
00674 
00675   if (p->flags & INFO_HAS_USER_BBOX) {
00676     wd0 =  p->bbox.urx - p->bbox.llx;
00677     ht0 =  p->bbox.ury - p->bbox.lly;
00678     xscale = I->attr.width * I->attr.xdensity / wd0;
00679     yscale = I->attr.height * I->attr.ydensity / ht0;
00680     d_x = -p->bbox.llx / wd0;
00681     d_y = -p->bbox.lly / ht0;
00682   } else {
00683     wd0 = I->attr.width * I->attr.xdensity;
00684     ht0 = I->attr.height * I->attr.ydensity;
00685     xscale = yscale = 1.0;
00686     d_x = 0.0;
00687     d_y = 0.0; 
00688   }
00689 
00690   if (wd0 == 0.0) {
00691     WARN("Image width=0.0!");
00692     wd0 = 1.0;
00693   }
00694   if (ht0 == 0.0) {
00695     WARN("Image height=0.0!");
00696     ht0 = 1.0;
00697   }
00698 
00699   if ( (p->flags & INFO_HAS_WIDTH ) &&
00700        (p->flags & INFO_HAS_HEIGHT) ) {
00701     s_x = p->width * xscale;
00702     s_y = (p->height + p->depth) * yscale;
00703     dp  = p->depth * yscale;
00704   } else if ( p->flags & INFO_HAS_WIDTH ) {
00705     s_x = p->width * xscale;
00706     s_y = s_x * ((double)I->attr.height / I->attr.width);
00707     dp  = 0.0;
00708   } else if ( p->flags & INFO_HAS_HEIGHT) {
00709     s_y = (p->height + p->depth) * yscale;
00710     s_x = s_y * ((double)I->attr.width / I->attr.height);
00711     dp  = p->depth * yscale;
00712   } else {
00713     s_x = wd0;
00714     s_y = ht0;
00715     dp  = 0.0;
00716   }
00717   T->a = s_x; T->c = 0.0;
00718   T->b = 0.0; T->d = s_y;
00719   T->e = d_x * s_x / xscale; T->f = d_y * s_y / yscale - dp;
00720 
00721   return;
00722 }
00723 
00724 
00725 static void
00726 scale_to_fit_F (pdf_tmatrix    *T,
00727                 transform_info *p,
00728                 pdf_ximage     *I)
00729 {
00730   double  s_x, s_y, d_x, d_y;
00731   double  wd0, ht0, dp;
00732 
00733   if (p->flags & INFO_HAS_USER_BBOX) {
00734     wd0 =  p->bbox.urx - p->bbox.llx;
00735     ht0 =  p->bbox.ury - p->bbox.lly;
00736     d_x = -p->bbox.llx;
00737     d_y = -p->bbox.lly;
00738   } else {
00739     wd0 = I->attr.bbox.urx - I->attr.bbox.llx;
00740     ht0 = I->attr.bbox.ury - I->attr.bbox.lly;
00741     d_x = 0.0;
00742     d_y = 0.0; 
00743   }
00744 
00745   if (wd0 == 0.0) {
00746     WARN("Image width=0.0!");
00747     wd0 = 1.0;
00748   }
00749   if (ht0 == 0.0) {
00750     WARN("Image height=0.0!");
00751     ht0 = 1.0;
00752   }
00753 
00754   if ( (p->flags & INFO_HAS_WIDTH ) &&
00755        (p->flags & INFO_HAS_HEIGHT) ) {
00756     s_x = p->width  / wd0;
00757     s_y = (p->height + p->depth) / ht0;
00758     dp  = p->depth;
00759   } else if ( p->flags & INFO_HAS_WIDTH ) {
00760     s_x = p->width  / wd0;
00761     s_y = s_x;
00762     dp  = 0.0;
00763   } else if ( p->flags & INFO_HAS_HEIGHT) {
00764     s_y = (p->height + p->depth) / ht0;
00765     s_x = s_y;
00766     dp  = p->depth;
00767   } else {
00768     s_x = s_y = 1.0;
00769     dp  = 0.0;
00770   }
00771 
00772   T->a = s_x; T->c = 0.0;
00773   T->b = 0.0; T->d = s_y;
00774   T->e = s_x * d_x; T->f = s_y * d_y - dp;
00775 
00776   return;
00777 }
00778 
00779 
00780 /* called from pdfdev.c and spc_html.c */
00781 int
00782 pdf_ximage_scale_image (int            id,
00783                         pdf_tmatrix    *M, /* return value for trans matrix */
00784                         pdf_rect       *r, /* return value for clipping */
00785                         transform_info *p  /* argument from specials */
00786                        )
00787 {
00788   struct ic_ *ic = &_ic;
00789   pdf_ximage *I;
00790 
00791   CHECK_ID(ic, id);
00792 
00793   I = GET_IMAGE(ic, id);
00794 
00795   pdf_setmatrix(M, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
00796 
00797   switch (I->subtype) {
00798   /* Reference: PDF Reference 1.5 v6, p.302
00799    *
00800    * An image can be placed on the output page in any desired position,
00801    * orientation, and size by using the cm operator to modify the current
00802    * transformation matrix (CTM) so as to map the unit square of user space
00803    * to the rectangle or parallelogram in which the image is to be painted.
00804    *
00805    * There is neither BBox nor Matrix key in the image XObject.
00806    * Everything must be controlled by the cm operator.
00807    *
00808    * The argument [p] contains the user-defined bounding box, the scailing
00809    * factor of which is bp as EPS and PDF. On the other hand, I->attr
00810    * contains the (sampling) width and the (sampling) height of the image.
00811    *
00812    * There is no problem if a bitmap image has density information.
00813    * Otherwise, DVIPDFM's ebb generates bounding box as 100px = 72bp = 1in.
00814    * In this case, screen captured images look bad. Moreover, DVIPDFM's ebb
00815    * ignores all density information and use just 100px = 72bp = 1in.
00816    *
00817    * On the other hand, pdfTeX uses 100px = 100bp to get a better quality
00818    * for screen captured images.
00819    *
00820    * DVIPDFMx's xbb generates bounding box as 100px = 100bp in the same
00821    * way as pdfTeX. Furthermore, it takes care of density information too.
00822    */
00823   case PDF_XOBJECT_TYPE_IMAGE:
00824     scale_to_fit_I(M, p, I);
00825     if (p->flags & INFO_HAS_USER_BBOX) {
00826       r->llx = p->bbox.llx / (I->attr.width * I->attr.xdensity);
00827       r->lly = p->bbox.lly / (I->attr.height * I->attr.ydensity);
00828       r->urx = p->bbox.urx / (I->attr.width * I->attr.xdensity);
00829       r->ury = p->bbox.ury / (I->attr.height * I->attr.ydensity);
00830     } else {
00831       r->llx = 0.0;
00832       r->lly = 0.0;
00833       r->urx = 1.0;
00834       r->ury = 1.0;
00835     }
00836     break;
00837   /* User-defined transformation and clipping are controlled by
00838    * the cm operator and W operator, explicitly */
00839   case PDF_XOBJECT_TYPE_FORM:
00840     scale_to_fit_F(M, p, I);
00841     if (p->flags & INFO_HAS_USER_BBOX) {
00842       r->llx = p->bbox.llx;
00843       r->lly = p->bbox.lly;
00844       r->urx = p->bbox.urx;
00845       r->ury = p->bbox.ury;
00846     } else { /* I->attr.bbox from the image bounding box */
00847       r->llx = I->attr.bbox.llx;
00848       r->lly = I->attr.bbox.lly;
00849       r->urx = I->attr.bbox.urx;
00850       r->ury = I->attr.bbox.ury;
00851     }
00852     break;
00853   }
00854 
00855   return  0;
00856 }
00857 
00858 
00859 /* Migrated from psimage.c */
00860 
00861 void set_distiller_template (char *s) 
00862 {
00863   if (_opts.cmdtmpl)
00864     RELEASE(_opts.cmdtmpl);
00865   if (!s || *s == '\0')
00866     _opts.cmdtmpl = NULL;
00867   else {
00868     _opts.cmdtmpl = NEW(strlen(s) + 1, char);
00869     strcpy(_opts.cmdtmpl, s);
00870   }
00871   return;
00872 }
00873 
00874 static int
00875 ps_include_page (pdf_ximage *ximage)
00876 {
00877   char  *distiller_template = _opts.cmdtmpl;
00878   char  *filename = ximage->filename;
00879   char  *temp;
00880   FILE  *fp;
00881   int    error = 0;
00882 
00883   if (!distiller_template) {
00884     WARN("No image converter available for converting file \"%s\" to PDF format.", filename);
00885     WARN(">> Please check if you have 'D' option in config file.");
00886     return  -1;
00887   }
00888 
00889   temp = dpx_create_temp_file();
00890   if (!temp) {
00891     WARN("Failed to create temporary file for image conversion: %s", filename);
00892     return  -1;
00893   }
00894 
00895   if (_opts.verbose > 1) {
00896     MESG("\n");
00897     MESG("pdf_image>> Converting file \"%s\" --> \"%s\" via:\n", filename, temp);
00898     MESG("pdf_image>>   %s\n", distiller_template);
00899     MESG("pdf_image>> ...");
00900   }
00901 
00902   error = dpx_file_apply_filter(distiller_template, filename, temp,
00903                                (unsigned short) pdf_get_version());
00904   if (error) {
00905     WARN("Image format conversion for \"%s\" failed...", filename);
00906     dpx_delete_temp_file(temp);
00907     return  error;
00908   }
00909 
00910   fp = MFOPEN(temp, FOPEN_RBIN_MODE);
00911   if (!fp) {
00912     WARN("Could not open conversion result \"%s\" for image \"%s\". Why?", temp, filename);
00913     dpx_delete_temp_file(temp);
00914     return  -1;
00915   }
00916   pdf_set_ximage_tempfile(ximage, temp);
00917   error = pdf_include_page(ximage, fp, temp);
00918   MFCLOSE(fp);
00919 
00920   /* See pdf_close_images for why we cannot delete temporary files here. */
00921 
00922   RELEASE(temp);
00923 
00924   if (error) {
00925     WARN("Failed to include image file \"%s\"", filename);
00926     WARN(">> Please check if");
00927     WARN(">>   %s", distiller_template);
00928     WARN(">>   %%o = output filename, %%i = input filename, %%b = input filename without suffix");
00929     WARN(">> can really convert \"%s\" to PDF format image.", filename);
00930   }
00931 
00932   return  error;
00933 }
00934 
00935 static int check_for_ps (FILE *image_file) 
00936 {
00937   rewind (image_file);
00938   mfgets (work_buffer, WORK_BUFFER_SIZE, image_file);
00939   if (!strncmp (work_buffer, "%!", 2))
00940     return 1;
00941   return 0;
00942 }