Back to index

tetex-bin  3.0
pdftoepdf.cc
Go to the documentation of this file.
00001 /*
00002 Copyright 1996-2004 Han The Thanh, <thanh@pdftex.org>
00003 
00004 This file is part of pdfTeX.
00005 
00006 pdfTeX is free software; you can redistribute it and/or modify
00007 it under the terms of the GNU General Public License as published by
00008 the Free Software Foundation; either version 2 of the License, or
00009 (at your option) any later version.
00010 
00011 pdfTeX is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with pdfTeX; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftoepdf.cc#51 $
00021 */
00022 
00023 #include <stdlib.h>
00024 #include <math.h>
00025 #include <stddef.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <ctype.h>
00029 #include <aconf.h>
00030 #include <GString.h>
00031 #include <gmem.h>
00032 #include <gfile.h>
00033 #include <config.h>
00034 #include "Object.h"
00035 #include "Stream.h"
00036 #include "Array.h"
00037 #include "Dict.h"
00038 #include "XRef.h"
00039 #include "Catalog.h"
00040 #include "Page.h"
00041 #include "GfxFont.h"
00042 #include "PDFDoc.h"
00043 #include "GlobalParams.h"
00044 #include "Error.h"
00045 
00046 #include "epdf.h"
00047 
00048 static const char perforce_id[] = 
00049     "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftoepdf.cc#51 $";
00050 
00051 /* we avoid reading all necessary kpathsea headers, but we need xstrdup */
00052 #ifdef __cplusplus
00053 extern "C" {
00054   extern KPSEDLL char *xstrdup (const char *);
00055 }
00056 #else
00057   extern KPSEDLL char *xstrdup (const char *);
00058 #endif
00059 
00060 #ifdef __cplusplus
00061 extern "C" {
00062 // FIXME: This definition is a duplicate from ../pdftexcoerce.h, which is
00063 // not usable here because of different macro definitions.
00064 extern integer pdflastpdfboxspec ;
00065 }
00066 #endif
00067 
00068 /*
00069  * Used flags below:
00070  * PDFTEX_COPY_PAGEGROUP
00071  *      if pdfTeX should copy a page group (a new feature in pdf1.4 for
00072  *      transparency) of an included file. The current support for this is
00073  *      most likely broken. pdfTeX will at least give a warning if this flag
00074  *      is not set. Surprisingly Acrobat and Jaws display files without a
00075  *      page group correctly, so it might be safe to not set the flag.
00076  *  See also PDFTEX_COPY_PAGEGROUP_NOFAIL
00077  * PDFTEX_COPY_PAGEGROUP_NOFAIL
00078  *      if set to false pdfTeX will treat a page group in an included file as
00079  *      an error and abort gracefully. This is only evaluated if
00080  *      PDFTEX_COPY_PAGEGROUP is set.
00081  */
00082 
00083 // FIXME: These definitions are duplicates from pdftexd.h
00084 /* #define PDF_PDF_BOX_SPEC_MEDIA 0 */
00085 /* #define PDF_PDF_BOX_SPEC_CROP  1 */
00086 /* #define PDF_PDF_BOX_SPEC_BLEED 2 */
00087 /* #define PDF_PDF_BOX_SPEC_TRIM  3 */
00088 /* #define PDF_PDF_BOX_SPEC_ART   4 */
00089 #define pdfpdfboxspecmedia ( 0 ) 
00090 #define pdfpdfboxspeccrop ( 1 ) 
00091 #define pdfpdfboxspecbleed ( 2 ) 
00092 #define pdfpdfboxspectrim ( 3 ) 
00093 #define pdfpdfboxspecart ( 4 ) 
00094 
00095 // The prefix for the PDF keys special to pdfTeX
00096 // This has been registered with Adobe by Hans Hagen
00097 #define pdfkeyprefix "PTEX"
00098 
00099 // PdfObject encapsulates the xpdf Object type, and properly 
00100 // frees its resources on destruction.
00101 // Use obj-> to access members of the Object, and
00102 // &obj to get a pointer to the object. 
00103 // It is no longer necessary to call Object::free explicitely.
00104 
00105 class PdfObject {
00106 public:
00107   PdfObject() { /* nothing */ }
00108   ~PdfObject() { iObject.free(); }
00109   Object* operator->() { return &iObject; }
00110   Object* operator&() { return &iObject; }
00111 private: // no copying or assigning
00112   PdfObject(const PdfObject &);
00113   void operator=(const PdfObject &);
00114 public:
00115   Object iObject;
00116 };
00117 
00118 // when copying the Resources of the selected page, all objects are copied
00119 // recusively top-down. Indirect objects however are not fetched during
00120 // copying, but get a new object number from pdftex and then will be
00121 // appended into a linked list. Duplicates are checked and removed from the
00122 // list of indirect objects during appending.
00123 
00124 enum InObjType {
00125     objFont,
00126     objFontDesc,
00127     objOther
00128 };
00129 
00130 struct InObj {
00131     Ref ref;            // ref in original PDF
00132     InObjType type;     // object type
00133     InObj *next;        // next entry in list of indirect objects
00134     integer num;        // new object number in output PDF
00135     fm_entry * fontmap; // pointer to font map entry
00136     integer enc_objnum;   // Encoding for objFont      
00137     int written;        // has it been written to output PDF?
00138 };
00139 
00140 struct UsedEncoding {
00141     integer enc_objnum;
00142     GfxFont *font;
00143     UsedEncoding *next;
00144 };
00145 
00146 static InObj *inObjList;
00147 static UsedEncoding *encodingList;
00148 static GBool isInit = gFalse;
00149 
00150 // --------------------------------------------------------------------
00151 // Maintain list of open embedded PDF files
00152 // --------------------------------------------------------------------
00153 
00154 struct PdfDocument {
00155     char *file_name;
00156     PDFDoc *doc;
00157     XRef *xref;
00158     InObj *inObjList;
00159     int occurences;     // number of references to the document; the doc can be
00160                         // deleted when this is negative
00161     PdfDocument *next;
00162 };
00163 
00164 static PdfDocument *pdfDocuments = 0;
00165 
00166 static XRef *xref = 0;
00167 
00168 // Returns pointer to PdfDocument record for PDF file.
00169 // Creates a new record if it doesn't exist yet.
00170 // xref is made current for the document.
00171 
00172 static PdfDocument *find_add_document(char *file_name)
00173 {
00174     PdfDocument *p = pdfDocuments;
00175     while (p && strcmp(p->file_name, file_name) != 0)
00176         p = p->next;
00177     if (p) {
00178         xref = p->xref;
00179         (p->occurences)++;
00180 #ifdef DEBUG
00181         fprintf(stderr, "\nIncrementing %s (%d)\n", p->file_name, p->occurences);
00182 #endif
00183         return p;
00184     }
00185     p = new PdfDocument;
00186     p->file_name = xstrdup(file_name);
00187     p->xref = xref = 0;
00188     p->occurences = 0;
00189 #ifdef DEBUG
00190     fprintf(stderr, "\nCreating %s (%d)\n", p->file_name, p->occurences);
00191 #endif
00192     GString *docName = new GString(p->file_name);
00193     p->doc = new PDFDoc(docName);  // takes ownership of docName
00194     if (!p->doc->isOk() || !p->doc->okToPrint()) {
00195         pdftex_fail("xpdf: reading PDF image failed");
00196         }
00197     p->inObjList = 0;
00198     p->next = pdfDocuments;
00199     pdfDocuments = p;
00200     return p;
00201 }
00202 
00203 // Deallocate a PdfDocument with all its resources
00204 static void delete_document(PdfDocument *pdf_doc)
00205 {
00206     PdfDocument **p = &pdfDocuments;
00207     while (*p && *p != pdf_doc)
00208       p = &((*p)->next);
00209     // should not happen:
00210     if (!*p) 
00211       return;
00212     // unlink from list
00213     *p = pdf_doc->next;
00214     // free pdf_doc's resources
00215     InObj *r, *n;
00216     for (r = pdf_doc->inObjList; r != 0; r = n) {
00217         n = r->next;
00218         delete r;
00219     }
00220     xref = pdf_doc->xref;
00221     delete pdf_doc->doc;
00222     xfree(pdf_doc->file_name);
00223     delete pdf_doc;
00224 }
00225 
00226 // Replacement for 
00227 //      Object *initDict(Dict *dict1){ initObj(objDict); dict = dict1; return this; }
00228 static void initDictFromDict (PdfObject &obj, Dict *dict)
00229 {
00230     obj->initDict(xref);
00231     for (int i = 0,
00232          l = dict->getLength(); 
00233          i < l; 
00234          i++) {
00235         Object obj1;
00236         obj->dictAdd(copyString(dict->getKey(i)), dict->getValNF(i, &obj1));
00237         }
00238 }    
00239 
00240 // --------------------------------------------------------------------
00241 
00242 static int addEncoding(GfxFont *gfont)
00243 {
00244     UsedEncoding *n;
00245     n = new UsedEncoding;
00246     n->next = encodingList;
00247     encodingList = n;
00248     n->font = gfont;
00249     n->enc_objnum = pdfnewobjnum();
00250     return n->enc_objnum;
00251 }
00252 
00253 #define addFont(ref, fontmap, enc_objnum) \
00254         addInObj(objFont, ref, fontmap, enc_objnum)
00255 
00256 #define addFontDesc(ref, fontmap) \
00257         addInObj(objFontDesc, ref, fontmap, 0)
00258 
00259 #define addOther(ref) \
00260         addInObj(objOther, ref, 0, 0)
00261 
00262 static int addInObj(InObjType type, Ref ref, fm_entry *f, integer e)
00263 {
00264     InObj *p, *q, *n = new InObj;
00265     if (ref.num == 0)
00266         pdftex_fail("pdf inclusion: invalid reference");
00267     n->ref = ref;
00268     n->type = type;
00269     n->next = 0;
00270     n->fontmap = f;
00271     n->enc_objnum = e;
00272     n->written = 0;
00273     if (inObjList == 0)
00274         inObjList = n;
00275     else {
00276         for (p = inObjList; p != 0; p = p->next) {
00277             if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
00278                 delete n;
00279                 return p->num;
00280             }
00281             q = p;
00282         }
00283         // it is important to add new objects at the end of the list,
00284         // because new objects are being added while the list is being
00285         // written out.
00286         q->next = n;
00287     }
00288     n->num = pdfnewobjnum();
00289     return n->num;
00290 }
00291 
00292 static void copyObject(Object *);
00293 
00294 static void copyName(char *s)
00295 {
00296     pdf_puts("/");
00297     for (; *s != 0; s++) {
00298         if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' ||
00299         *s == '.' || *s == '-' )
00300             pdfout(*s);
00301         else
00302             pdf_printf("#%.2X", *s & 0xFF);
00303     }
00304 }
00305 
00306 static void copyDictEntry(Object *obj, int i)
00307 {
00308     PdfObject obj1;
00309     copyName(obj->dictGetKey(i));
00310     pdf_puts(" ");
00311     obj->dictGetValNF(i, &obj1);
00312     copyObject(&obj1);
00313     pdf_puts("\n");
00314 }
00315 
00316 static void copyDict(Object *obj)
00317 {
00318     int i, l;
00319     if (!obj->isDict())
00320         pdftex_fail("pdf inclusion: invalid dict type <%s>", 
00321                     obj->getTypeName());
00322     for (i = 0, l = obj->dictGetLength(); i < l; ++i)
00323         copyDictEntry(obj, i);
00324 }
00325 
00326 static void copyFontDict(Object *obj, InObj *r)
00327 {
00328     int i, l;
00329     char *key;
00330     if (!obj->isDict())
00331         pdftex_fail("pdf inclusion: invalid dict type <%s>", 
00332                     obj->getTypeName());
00333     pdf_puts("<<\n");
00334     if (r->type == objFont) { // Font dict
00335         for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
00336             key = obj->dictGetKey(i);
00337             if (strcmp("BaseFont", key) == 0 || 
00338                 strcmp("Encoding", key) == 0)
00339                 continue; // skip original values
00340             copyDictEntry(obj, i);
00341         }
00342         // write new BaseFont and Encoding
00343         pdf_printf("/BaseFont %i 0 R\n", (int)get_fontname(r->fontmap)); 
00344         pdf_printf("/Encoding %i 0 R\n", (int)r->enc_objnum); 
00345     }
00346     else { // FontDescriptor dict
00347         for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
00348             key = obj->dictGetKey(i);
00349             if (strcmp("FontName", key) == 0 ||
00350                 strncmp("FontFile", key, strlen("FontFile")) == 0)
00351                 continue; // ignore original FontFile/FontName
00352             if (strcmp("CharSet", key) == 0)
00353                 continue; // ignore CharSet
00354             copyDictEntry(obj, i);
00355         }
00356         // write new FontName and FontFile
00357         pdf_printf("/FontName %i 0 R\n", (int)get_fontname(r->fontmap)); 
00358         pdf_printf("/FontFile %i 0 R\n", (int)get_fontfile(r->fontmap));
00359     }
00360     pdf_puts(">>");
00361 }
00362 
00363 static void copyStream(Stream *str)
00364 {
00365     int c;
00366     str->reset();
00367     while ((c = str->getChar()) != EOF)
00368         pdfout(c);
00369 }
00370 
00371 static void copyProcSet(Object *obj)
00372 {
00373     int i, l;
00374     PdfObject procset;
00375     if (!obj->isArray())
00376         pdftex_fail("pdf inclusion: invalid ProcSet array type <%s>", 
00377                     obj->getTypeName());
00378     pdf_puts("/ProcSet [ ");
00379     for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
00380         obj->arrayGetNF(i, &procset);
00381         if (!procset->isName())
00382             pdftex_fail("pdf inclusion: invalid ProcSet entry type <%s>", 
00383                         procset->getTypeName());
00384         copyName(procset->getName());
00385         pdf_puts(" ");
00386     }
00387     pdf_puts("]\n");
00388 }
00389 
00390 static void copyFont(char *tag, Object *fontRef)
00391 {
00392     PdfObject fontdict, subtype, basefont, fontdescRef, fontdesc, charset;
00393     GfxFont *gfont;
00394     fm_entry *fontmap;
00395     // Check whether the font has already been embedded before analysing it.
00396     InObj *p;
00397     Ref ref = fontRef->getRef();
00398     for (p = inObjList; p; p = p->next) {
00399         if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
00400             copyName(tag);
00401             pdf_printf(" %d 0 R ", p->num);
00402             return;
00403         }
00404     }
00405     fontRef->fetch(xref, &fontdict);
00406     if (!fontdict->isDict())
00407         pdftex_fail("pdf inclusion: invalid font dict type <%s>", 
00408                     fontdict->getTypeName());
00409     fontdict->dictLookup("Subtype", &subtype);
00410     if (!subtype->isName())
00411         pdftex_fail("pdf inclusion: invalid font Subtype entry type <%s>", 
00412                     subtype->getTypeName());
00413     /* only handle Type1 fonts; others will be copied */
00414     if (strcmp(subtype->getName(), "Type1") != 0 ) {
00415         copyName(tag);
00416         pdf_puts(" ");
00417         copyObject(fontRef);
00418         return;
00419     }
00420     fontdict->dictLookup("BaseFont", &basefont);
00421     if (!basefont->isName())
00422         pdftex_fail("pdf inclusion: invalid font BaseFont entry type <%s>", 
00423                     basefont->getTypeName());
00424     fontmap = lookup_fontmap(basefont->getName());
00425     if (fontmap != NULL && is_type1(fontmap) &&
00426         fontdict->dictLookupNF("FontDescriptor", &fontdescRef) && 
00427         fontdescRef->isRef() && fontdescRef->fetch(xref, &fontdesc) &&
00428         fontdesc->isDict()) {
00429         if (fontdesc->dictLookup("CharSet", &charset) && 
00430                 charset->isString() && is_subsetable(fontmap))
00431             mark_glyphs(fontmap, charset->getString()->getCString());
00432         else
00433             embed_whole_font(fontmap);
00434         addFontDesc(fontdescRef->getRef(), fontmap);
00435     }
00436     copyName(tag);
00437     if (fontdesc->isDict()) {
00438         gfont = GfxFont::makeFont(xref, tag, fontRef->getRef(), fontdict->getDict());
00439         pdf_printf(" %d 0 R ", addFont(fontRef->getRef(), fontmap, 
00440                                        addEncoding(gfont)));
00441     }
00442     else
00443         pdf_printf(" %d 0 R ", addOther(fontRef->getRef()));
00444 }
00445 
00446 static void copyFontResources(Object *obj)
00447 {
00448     PdfObject fontRef;
00449     int i, l;
00450     if (!obj->isDict())
00451         pdftex_fail("pdf inclusion: invalid font resources dict type <%s>", 
00452                     obj->getTypeName());
00453     pdf_puts("/Font << ");
00454     for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
00455         obj->dictGetValNF(i, &fontRef);
00456         if (fontRef->isRef())
00457             copyFont(obj->dictGetKey(i), &fontRef);
00458         else
00459             pdftex_fail("pdf inclusion: invalid font in reference type <%s>", 
00460                         fontRef->getTypeName());
00461     }
00462     pdf_puts(">>\n");
00463 }
00464 
00465 static void copyOtherResources(Object *obj, char *key)
00466 {
00467     /* copies all other resources (write_epdf handles Fonts and ProcSets),
00468      * but gives a warning if an object is not a dictionary.
00469      */
00470     if (!obj->isDict())
00471         //FIXME: Write the message only to the log file
00472         pdftex_warn("pdf inclusion: invalid other resource which is no dict"
00473                     " (key '%s', type <%s>); copying it anyway.", 
00474                     key,
00475                     obj->getTypeName());
00476     copyName(key);
00477     pdf_puts(" ");
00478     copyObject(obj);
00479 }
00480 
00481 /* converts double to string; very small and very large numbers are NOT
00482  * converted to scientific notation.
00483  * n must be a number or real confirming to the implementation limits of PDF as
00484  * specified in appendix C.1 of the pdf ref.  
00485  * These are:
00486  * maximum value of ints is +2^32
00487  * maximum value of reals is +2^15
00488  * smalles values of reals is 1/(2^16)
00489  */
00490 static char *
00491 convertNumToPDF(double n) 
00492 {
00493     static const int precision = 6;
00494     static const int fact = (int) 1E6;        /* must be 10^precision */
00495     static const double epsilon = 0.5E-6; /* 2epsilon must be 10^-precision */
00496     static char buf[64];
00497     // handle very small values: return 0
00498     if (fabs(n) < epsilon) {buf[0] = '0'; buf[1] = '\0';}
00499     else {
00500         char ints[64];
00501         int bindex = 0, sindex = 0;
00502         int ival, fval; 
00503         // handle the sign part if n is negative
00504         if (n < 0) {
00505             buf[bindex++] = '-';
00506             n = -n;    
00507         }
00508         n += epsilon; // for rounding
00509         // handle the integer part, simply with sprintf
00510         ival = (int)floor(n);
00511         n -= ival;
00512         sprintf(ints, "%d", ival);
00513         while (ints[sindex] != 0) buf[bindex++] = ints[sindex++];
00514         // handle the fractional part up to 'precision' digits
00515         fval = (int)floor(n*fact);
00516         if (fval) {
00517             // set a dot
00518             buf[bindex++] = '.';
00519             sindex = bindex + precision;
00520             buf[sindex--] = '\0';
00521             // fill up trailing zeros with the string terminator NULL
00522             while (((fval % 10) == 0) && (sindex >= bindex)) {
00523                 buf[sindex--] = '\0';
00524                 fval /= 10;
00525             }
00526             // fill up the fractional part back to front
00527             while (sindex >= bindex) {
00528                 buf[sindex--] = (fval % 10) + '0';
00529                 fval /= 10;
00530             }
00531         } else buf[bindex++] = 0;
00532     }
00533     return (char *)buf;
00534 }
00535 
00536 static void copyObject(Object *obj)
00537 {
00538     PdfObject obj1;
00539     int  i, l, c;
00540     Ref ref;
00541     char *p;
00542     GString *s;
00543     if (obj->isBool()) {
00544         pdf_printf("%s", obj->getBool() ? "true" : "false");
00545     }
00546     else if (obj->isInt()) {
00547         pdf_printf("%i", obj->getInt());
00548     }
00549     else if (obj->isReal()) {
00550         pdf_printf("%s", convertNumToPDF(obj->getReal()));
00551     }
00552     else if (obj->isNum()) {
00553         pdf_printf("%s", convertNumToPDF(obj->getNum()));
00554     }
00555     else if (obj->isString()) {
00556         s = obj->getString();
00557         p = s->getCString();
00558         l = s->getLength();
00559         if (strlen(p) == (unsigned int)l) {
00560             pdf_puts("(");
00561             for (; *p != 0; p++) {
00562                 c = (unsigned char)*p;
00563                 if (c == '(' || c == ')' || c == '\\')
00564                     pdf_printf("\\%c", c);
00565                 else if (c < 0x20 || c > 0x7F)
00566                     pdf_printf("\\%03o", c);
00567                 else
00568                     pdfout(c);
00569             }
00570             pdf_puts(")");
00571         }
00572         else {
00573             pdf_puts("<");
00574             for (i = 0; i < l; i++) {
00575                 c = s->getChar(i) & 0xFF;
00576                 pdf_printf("%.2x", c);
00577             }
00578             pdf_puts(">");
00579         }
00580     }
00581     else if (obj->isName()) {
00582         copyName(obj->getName());
00583     }
00584     else if (obj->isNull()) {
00585         pdf_puts("null");
00586     }
00587     else if (obj->isArray()) {
00588         pdf_puts("[");
00589         for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
00590             obj->arrayGetNF(i, &obj1);
00591             if (!obj1->isName())
00592                 pdf_puts(" ");
00593             copyObject(&obj1);
00594         }
00595         pdf_puts("]");
00596     }
00597     else if (obj->isDict()) {
00598         pdf_puts("<<\n");
00599         copyDict(obj);
00600         pdf_puts(">>");
00601     }
00602     else if (obj->isStream()) {
00603         initDictFromDict (obj1, obj->streamGetDict());
00604         obj->streamGetDict()->incRef();
00605         pdf_puts("<<\n");
00606         copyDict(&obj1);
00607         pdf_puts(">>\n");
00608         pdf_puts("stream\n");
00609         copyStream(obj->getStream()->getBaseStream());
00610         pdf_puts("endstream");
00611     }
00612     else if (obj->isRef()) {
00613         ref = obj->getRef();
00614         if (ref.num == 0) {
00615             pdftex_warn("pdf inclusion: reference to invalid object was replaced by <null>");
00616             pdf_puts("null");
00617         }
00618         else
00619             pdf_printf("%d 0 R", addOther(ref));
00620     }
00621     else {
00622         pdftex_fail("pdf inclusion: type <%s> cannot be copied", 
00623                     obj->getTypeName());
00624     }
00625 }
00626 
00627 static void writeRefs()
00628 {
00629     InObj *r;
00630     for (r = inObjList; r != 0; r = r->next) {
00631         if (!r->written) {
00632             Object obj1;
00633         r->written = 1;
00634         zpdfbeginobj(r->num);
00635         xref->fetch(r->ref.num, r->ref.gen, &obj1);
00636         if (r->type == objFont || r->type == objFontDesc)
00637             copyFontDict(&obj1, r);
00638         else
00639                 copyObject(&obj1);
00640         pdf_puts("\n");
00641         pdfendobj();
00642         obj1.free();
00643     }
00644     }
00645 }
00646 
00647 static void writeEncodings()
00648 {
00649     UsedEncoding *r, *n;
00650     char *glyphNames[MAX_CHAR_CODE + 1], *s;
00651     int i;
00652     for (r = encodingList; r != 0; r = r->next) {
00653       for (i = 0; i <= MAX_CHAR_CODE; i++) {
00654       if (r->font->isCIDFont()) {
00655         pdftex_warn("pdf inclusion: CID font included, encoding maybe wrong");
00656       }
00657       if ((s = ((Gfx8BitFont *)r->font)->getCharName(i)) != 0)
00658         glyphNames[i] = s;
00659       else
00660         glyphNames[i] = notdef;
00661       }
00662         write_enc(glyphNames, NULL, r->enc_objnum);
00663     }
00664     for (r = encodingList; r != 0; r = n) {
00665         n = r->next;
00666         delete r->font;
00667         delete r;
00668     }
00669 }
00670 
00671 /* Reads various information about the pdf and sets it up for later inclusion.
00672  * This will fail if the pdf version of the pdf is higher than
00673  * minor_pdf_version_wanted or page_name is given and can not be found.
00674  * It makes no sense to give page_name _and_ page_num.
00675  * Returns the page number.
00676  */
00677 integer 
00678 read_pdf_info(char *image_name, char *page_name, integer page_num,
00679               integer minor_pdf_version_wanted, integer always_use_pdf_pagebox,
00680               integer pdf_inclusion_errorlevel)
00681 {
00682     PdfDocument *pdf_doc;
00683     Page *page;
00684     int rotate;
00685     PDFRectangle *pagebox;
00686     float pdf_version_found, pdf_version_wanted;
00687     // initialize
00688     if (!isInit) {
00689         globalParams = new GlobalParams();
00690         globalParams->setErrQuiet(gFalse);
00691         isInit = gTrue;
00692     }
00693     // open PDF file
00694     pdf_doc = find_add_document(image_name);
00695     epdf_doc = (void *) pdf_doc;
00696 #ifdef DEBUG
00697     fprintf(stderr, "\nReading information on %s\n", pdf_doc->file_name);
00698 #endif
00699     // check pdf version
00700     // this works only for pdf 1.x -- but since any versions of pdf newer
00701     // than 1.x will not be backwards compatible to pdf 1.x, pdfTeX will
00702     // then have to changed drastically anyway.
00703     pdf_version_found = pdf_doc->doc->getPDFVersion();
00704     pdf_version_wanted = 1 + (minor_pdf_version_wanted * 0.1);
00705     if (pdf_version_found > pdf_version_wanted) {
00706         char msg[] = "pdf inclusion: found pdf version <%.1f>, but at most version <%.1f> allowed";
00707         if (pdf_inclusion_errorlevel > 0) {
00708             pdftex_fail(msg, pdf_version_found, pdf_version_wanted);
00709         } else {
00710             pdftex_warn(msg, pdf_version_found, pdf_version_wanted);
00711         }
00712     }
00713     epdf_num_pages = pdf_doc->doc->getCatalog()->getNumPages();
00714     if (page_name) {
00715         // get page by name
00716         GString name(page_name);
00717         LinkDest *link = pdf_doc->doc->findDest(&name);
00718         if (link == 0 || !link->isOk())
00719             pdftex_fail("pdf inclusion: invalid destination <%s>",
00720                 page_name);
00721         Ref ref = link->getPageRef();
00722         page_num = pdf_doc->doc->getCatalog()->findPage(ref.num, ref.gen);
00723         if (page_num == 0)
00724             pdftex_fail("pdf inclusion: destination is not a page <%s>",
00725                 page_name);
00726         delete link;
00727     } else {
00728         // get page by number
00729         if (page_num <= 0 || page_num > epdf_num_pages)
00730         pdftex_fail("pdf inclusion: required page does not exist <%i>", 
00731             epdf_num_pages);
00732     }
00733     // get the required page
00734     page = pdf_doc->doc->getCatalog()->getPage(page_num);
00735 
00736     // get the pagebox (media, crop...) to use.
00737     // always_use_pdf_pagebox can set in the config file to override the
00738     // setting through pdfximage.
00739     if (always_use_pdf_pagebox < 1) {
00740         switch (pdflastpdfboxspec) {
00741         case pdfpdfboxspeccrop:
00742             pagebox = page->getCropBox();
00743             break;
00744         
00745         case pdfpdfboxspecbleed:
00746             pagebox = page->getBleedBox();
00747             break;
00748         
00749         case pdfpdfboxspectrim:
00750             pagebox = page->getTrimBox();
00751             break;
00752         
00753         case pdfpdfboxspecart:
00754             pagebox = page->getArtBox();
00755             break;
00756 
00757         default:
00758             pagebox = page->getMediaBox();
00759             }
00760         }
00761     else {
00762         switch (always_use_pdf_pagebox) {
00763         case 1 : 
00764             pagebox = page->getMediaBox();
00765             break;
00766         case 2 : 
00767             pagebox = page->getCropBox();
00768             break;
00769         case 3 : 
00770             pagebox = page->getBleedBox();
00771             break;
00772         case 4 : 
00773             pagebox = page->getTrimBox();
00774             break;
00775         default : // 5 and larger
00776             pagebox = page->getArtBox();
00777             }
00778         }
00779 #ifdef DEBUG
00780     fprintf(stderr, 
00781             "\npagebox->x1: %.8f, pagebox->x2: %.8f, pagebox->y1: %.8f, pagebox->y2: %.8f\n", 
00782             pagebox->x1, pagebox->x2, pagebox->y1, pagebox->y2);
00783 #endif
00784     epdf_width = pagebox->x2 - pagebox->x1;
00785     epdf_height = pagebox->y2 - pagebox->y1;
00786     epdf_orig_x = pagebox->x1;
00787     epdf_orig_y = pagebox->y1;
00788     
00789     rotate = page->getRotate();
00790     // handle page rotation and adjust dimens as needed
00791     if (rotate != 0) {
00792         if (rotate % 90 == 0) {
00793             // handle only the simple case: multiple of 90s.
00794             // these are the only values allowed according to the
00795             // reference (v1.3, p.78).
00796             // 180 needs no special treatment here
00797             register float f;
00798             switch (rotate) {
00799                 case  90: f = epdf_height; epdf_height = epdf_width; epdf_width = f;  break;
00800                 case 270: f = epdf_height; epdf_height = epdf_width; epdf_width = f;  break;
00801                 }
00802             }
00803         }
00804     pdf_doc->xref = pdf_doc->doc->getXRef();
00805     return page_num;
00806 }
00807 
00808 /* writes the current epf_doc.
00809  * Here the included pdf is copied, so most errors that can happen during pdf
00810  * inclusion will arise here.
00811  */
00812 void 
00813 write_epdf(void)
00814 {
00815     Page *page;
00816     PdfObject contents, obj1, obj2;
00817     PdfObject group, metadata, pieceinfo, separationInfo;
00818     Object info;
00819     char *key;
00820     int i, l;
00821     int rotate;
00822     double scale[6] = {0, 0, 0, 0, 0, 0};
00823     PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
00824     (pdf_doc->occurences)--;
00825 #ifdef DEBUG
00826     fprintf(stderr, "\nDecrementing %s (%d)\n", pdf_doc->file_name, pdf_doc->occurences);
00827 #endif
00828     xref = pdf_doc->xref;
00829     inObjList = pdf_doc->inObjList;
00830     encodingList = 0;
00831     page = pdf_doc->doc->getCatalog()->getPage(epdf_selected_page);
00832     rotate = page->getRotate();
00833     PDFRectangle *pagebox;
00834     // write the Page header
00835     pdf_puts("/Type /XObject\n");
00836     pdf_puts("/Subtype /Form\n");
00837     pdf_puts("/FormType 1\n");
00838 
00839     // write additional information
00840     pdf_printf("/%s.FileName (%s)\n", pdfkeyprefix, 
00841                convertStringToPDFString(pdf_doc->file_name));
00842     pdf_printf("/%s.PageNumber %i\n", pdfkeyprefix, epdf_selected_page);
00843     pdf_doc->doc->getDocInfoNF(&info);
00844     if (info.isRef()) {
00845         // the info dict must be indirect (pdf ref p.61)
00846         pdf_printf("/%s.InfoDict ", pdfkeyprefix);
00847         pdf_printf("%d 0 R \n", addOther(info.getRef()));
00848         }
00849   
00850     // get the pagebox (media, crop...) to use.
00851     // epdf_always_use_pdf_pagebox is a copy of always_use_pdf_pagebox which
00852     // can set in the config file to override the setting through pdfximage.
00853     if (epdf_always_use_pdf_pagebox < 1) {
00854         switch (epdf_page_box) {
00855         case pdfpdfboxspeccrop:
00856             pagebox = page->getCropBox();
00857             break;
00858       
00859         case pdfpdfboxspecbleed:
00860             pagebox = page->getBleedBox();
00861             break;
00862         
00863         case pdfpdfboxspectrim:
00864             pagebox = page->getTrimBox();
00865             break;
00866         
00867         case pdfpdfboxspecart:
00868             pagebox = page->getArtBox();
00869             break;
00870        
00871         default:
00872             pagebox = page->getMediaBox();
00873             }
00874         }
00875     else {
00876         switch (epdf_always_use_pdf_pagebox) {
00877         case 1 : 
00878             pagebox = page->getMediaBox();
00879             break;
00880         case 2 : 
00881             pagebox = page->getCropBox();
00882             break;
00883         case 3 : 
00884             pagebox = page->getBleedBox();
00885             break;
00886         case 4 : 
00887             pagebox = page->getTrimBox();
00888             break;
00889         default : // 5 and larger
00890             pagebox = page->getArtBox();
00891             }
00892         }
00893 #ifdef DEBUG
00894     fprintf(stderr, 
00895             "\npagebox->x1: %.8f, pagebox->x2: %.8f, pagebox->y1: %.8f, pagebox->y2: %.8f\n", 
00896             pagebox->x1, pagebox->x2, pagebox->y1, pagebox->y2);
00897 #endif
00898 
00899     // handle page rotation
00900     if (rotate != 0) {
00901         if (rotate % 90 == 0) {
00902             // this handles only the simple case: multiple of 90s but these
00903             // are the only values allowed according to the reference
00904             // (v1.3, p.78).
00905             // the image is rotated around its center.
00906             // the /Rotate key is clockwise while the matrix is
00907             // counterclockwise :-%
00908             tex_printf (", page is rotated %d degrees", rotate);
00909             switch (rotate) {
00910                 case  90: scale[1] = -1; scale[2] = 1; scale[4] = pagebox->x1 - pagebox->y1; scale[5] = pagebox->y1 + pagebox->x2; break;
00911                 case 180: scale[0] = scale[3] = -1;    scale[4] = pagebox->x1 + pagebox->x2; scale[5] = pagebox->y1 + pagebox->y2; break; // width and height are exchanged
00912                 case 270: scale[1] = 1; scale[2] = -1; scale[4] = pagebox->x1 + pagebox->y2; scale[5] = pagebox->y1 - pagebox->x1; break;
00913                 }
00914             }
00915         }
00916     else {
00917         scale[0] = scale[3] = 1;
00918         }
00919 
00920     pdf_printf("/Matrix [%.8f %.8f %.8f %.8f %.8f %.8f]\n",
00921         scale[0],
00922         scale[1],
00923         scale[2],
00924         scale[3],
00925         scale[4],
00926         scale[5]);
00927 
00928     pdf_printf("/BBox [%.8f %.8f %.8f %.8f]\n",
00929                pagebox->x1,
00930                pagebox->y1,
00931                pagebox->x2,
00932                pagebox->y2);
00933 
00934     // write the page Group if it's there
00935     if (page->getGroup() != NULL) {
00936 #if PDFTEX_COPY_PAGEGROUP
00937 #   if PDFTEX_COPY_PAGEGROUP_NOFAIL
00938         // FIXME: This will most likely produce incorrect PDFs :-(
00939         initDictFromDict(group, page->getGroup());
00940         if (group->dictGetLength() > 0) {
00941             pdf_puts("/Group ");
00942             copyObject (&group);
00943             pdf_puts("\n");
00944         }
00945 #   else
00946         // FIXME: currently we don't know how to handle Page Groups so we abort gracefully :-(
00947         pdftex_fail("pdf inclusion: Page Group detected which pdfTeX can't handle. Sorry.");
00948 #   endif
00949 #else
00950         // FIXME: currently we don't know how to handle Page Groups so we at least give a warning :-(
00951         pdftex_warn("pdf inclusion: Page Group detected which pdfTeX can't handle. Ignoring it.");
00952 #endif
00953     }
00954     
00955     // write the page Metadata if it's there
00956     if (page->getMetadata() != NULL) {
00957         metadata->initStream(page->getMetadata());
00958         pdf_puts("/Metadata ");
00959         copyObject (&metadata);
00960         pdf_puts("\n");
00961     }
00962     
00963     // write the page PieceInfo if it's there
00964     if (page->getPieceInfo() != NULL) {
00965         initDictFromDict (pieceinfo, page->getPieceInfo());
00966         if (pieceinfo->dictGetLength() > 0) {
00967             pdf_puts("/PieceInfo ");
00968             copyObject (&pieceinfo);
00969             pdf_puts("\n");
00970         }
00971     }
00972     
00973     // write the page SeparationInfo if it's there
00974     if (page->getSeparationInfo() != NULL) {
00975         initDictFromDict (separationInfo, page->getSeparationInfo());
00976         if (separationInfo->dictGetLength() > 0) {
00977             pdf_puts("/SeparationInfo ");
00978             copyObject (&separationInfo);
00979             pdf_puts("\n");
00980         }
00981     }
00982     
00983     // write the Resources dictionary
00984     if (page->getResourceDict() == NULL) {
00985         // Resources can be missing (files without them have been spotted
00986         // in the wild). This violates the pdf spec, which claims they are
00987         // required, but all RIPs accept them.  
00988         // We "replace" them with empty Resources.
00989         pdftex_warn("pdf inclusion: no /Resources detected. Replacing with empty /Resources.");
00990         pdf_puts("/Resources <<>>\n");
00991         }
00992     else {
00993         initDictFromDict (obj1, page->getResourceDict());
00994         page->getResourceDict()->incRef();
00995         if (!obj1->isDict())
00996             pdftex_fail("pdf inclusion: invalid resources dict type <%s>", 
00997                         obj1->getTypeName());
00998         pdf_puts("/Resources <<\n");
00999         for (i = 0, l = obj1->dictGetLength(); i < l; ++i) {
01000             obj1->dictGetVal(i, &obj2);
01001             key = obj1->dictGetKey(i);
01002             if (strcmp("Font", key) == 0)
01003                 copyFontResources(&obj2);
01004             else if (strcmp("ProcSet", key) == 0)
01005                 copyProcSet(&obj2);
01006             else
01007                 copyOtherResources(&obj2, key);
01008             }
01009         pdf_puts(">>\n");
01010     }
01011     // write the page contents
01012     page->getContents(&contents);
01013     if (contents->isStream()) {
01014         initDictFromDict (obj1, contents->streamGetDict());
01015         contents->streamGetDict()->incRef();
01016         copyDict(&obj1);
01017         pdf_puts(">>\nstream\n");
01018         copyStream(contents->getStream()->getBaseStream());
01019         pdf_puts("endstream\n");
01020         pdfendobj();
01021     }
01022     else if (contents->isArray()) {
01023         pdfbeginstream();
01024         for (i = 0, l = contents->arrayGetLength(); i < l; ++i) {
01025         Object contentsobj;
01026             copyStream((contents->arrayGet(i, &contentsobj))->getStream());
01027         contentsobj.free();
01028         }
01029         pdfendstream();
01030     }
01031     else {// the contents are optional, but we need to include an empty stream
01032         pdfbeginstream();
01033         pdfendstream();
01034     }
01035     // write out all indirect objects
01036     writeRefs();
01037     // write out all used encodings (and delete list)
01038     writeEncodings();
01039     // save object list, xref
01040     pdf_doc->inObjList = inObjList;
01041     pdf_doc->xref = xref;
01042 }
01043 
01044 // Called when an image has been written and it's resources in image_tab are
01045 // freed and it's not referenced anymore.
01046 void 
01047 epdf_delete()
01048 {
01049     PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
01050     xref = pdf_doc->xref;
01051     if (pdf_doc->occurences < 0) {
01052 #ifdef DEBUG
01053         fprintf(stderr, "\nDeleting %s\n", pdf_doc->file_name);
01054 #endif
01055         delete_document(pdf_doc);
01056     }
01057 }
01058 
01059 // Called when PDF embedding system is finalized.
01060 // Now deallocate all remaining PdfDocuments.
01061 void epdf_check_mem()
01062 {
01063     if (isInit) {
01064         PdfDocument *p, *n;
01065     for (p = pdfDocuments; p; p = n) {
01066         n = p->next;
01067         delete_document(p);
01068     }
01069     // see above for globalParams
01070     delete globalParams;
01071     }
01072 }
01073 // vi:ts=4:tw=79:expandtab:ai: