1% pdftoepdf.w
2%
3% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
4% Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
5%
6% This file is part of LuaTeX.
7%
8% LuaTeX is free software; you can redistribute it and/or modify it under
9% the terms of the GNU General Public License as published by the Free
10% Software Foundation; either version 2 of the License, or (at your
11% option) any later version.
12%
13% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
14% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16% License for more details.
17%
18% You should have received a copy of the GNU General Public License along
19% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
20
21@ @c
22
23
24// define DEBUG
25#define __STDC_FORMAT_MACROS /* for PRId64 etc.  */
26
27#include "image/epdf.h"
28
29// This file is mostly C and not very much C++; it's just used to interface
30// the functions of xpdf, which happens to be written in C++.
31
32static GBool isInit = gFalse;
33
34//**********************************************************************
35// Maintain AVL tree of all PDF files for embedding
36
37static avl_table *PdfDocumentTree = NULL;
38
39// AVL sort PdfDocument into PdfDocumentTree by file_path
40
41static int CompPdfDocument(const void *pa, const void *pb, void * /*p */ )
42{
43    return strcmp(((const PdfDocument *) pa)->file_path,
44                  ((const PdfDocument *) pb)->file_path);
45}
46
47// Returns pointer to PdfDocument structure for PDF file.
48
49static PdfDocument *findPdfDocument(char *file_path)
50{
51    PdfDocument *pdf_doc, tmp;
52    assert(file_path != NULL);
53    if (PdfDocumentTree == NULL)
54        return NULL;
55    tmp.file_path = file_path;
56    pdf_doc = (PdfDocument *) avl_find(PdfDocumentTree, &tmp);
57    return pdf_doc;
58}
59
60#define PDF_CHECKSUM_SIZE 32
61
62static char *get_file_checksum(char *a, file_error_mode fe)
63{
64    struct stat finfo;
65    char *ck = NULL;
66    if (stat(a, &finfo) == 0) {
67        off_t size = finfo.st_size;
68        time_t mtime = finfo.st_mtime;
69        ck = (char *) malloc(PDF_CHECKSUM_SIZE);
70        if (ck == NULL)
71            luatex_fail("PDF inclusion: out of memory while processing '%s'",
72                        a);
73        snprintf(ck, PDF_CHECKSUM_SIZE, "%" PRIu64 "_%" PRIu64, (uint64_t) size,
74                 (uint64_t) mtime);
75   } else {
76        switch (fe) {
77        case FE_FAIL:
78            luatex_fail("PDF inclusion: could not stat() file '%s'", a);
79            break;
80        case FE_RETURN_NULL:
81            if (ck != NULL)
82                free(ck);
83            ck = NULL;
84            break;
85        default:
86            assert(0);
87        }
88    }
89    return ck;
90}
91
92// Returns pointer to PdfDocument structure for PDF file.
93// Creates a new PdfDocument structure if it doesn't exist yet.
94// When fe = FE_RETURN_NULL, the function returns NULL in error case.
95
96PdfDocument *refPdfDocument(char *file_path, file_error_mode fe)
97{
98    char *checksum;
99    PdfDocument *pdf_doc;
100    PDFDoc *doc = NULL;
101    GooString *docName = NULL;
102    int new_flag = 0;
103    if ((checksum = get_file_checksum(file_path, fe)) == NULL) {
104        assert(fe == FE_RETURN_NULL);
105        return (PdfDocument *) NULL;
106    }
107    assert(checksum != NULL);
108    if ((pdf_doc = findPdfDocument(file_path)) == NULL) {
109#ifdef DEBUG
110        fprintf(stderr, "\nDEBUG: New PdfDocument %s\n", file_path);
111#endif
112        new_flag = 1;
113        pdf_doc = new PdfDocument;
114        pdf_doc->file_path = xstrdup(file_path);
115        pdf_doc->checksum = checksum;
116        pdf_doc->doc = NULL;
117        pdf_doc->inObjList = NULL;
118        pdf_doc->ObjMapTree = NULL;
119        pdf_doc->occurences = 0;        // 0 = unreferenced
120        pdf_doc->pc = 0;
121    } else {
122#ifdef DEBUG
123        fprintf(stderr, "\nDEBUG: Found PdfDocument %s (%d)\n",
124                pdf_doc->file_path, pdf_doc->occurences);
125#endif
126        assert(pdf_doc->checksum != NULL);
127        if (strncmp(pdf_doc->checksum, checksum, PDF_CHECKSUM_SIZE) != 0) {
128            luatex_fail("PDF inclusion: file has changed '%s'", file_path);
129        }
130        free(checksum);
131    }
132    assert(pdf_doc != NULL);
133    if (pdf_doc->doc == NULL) {
134#ifdef DEBUG
135        fprintf(stderr, "\nDEBUG: New PDFDoc %s (%d)\n",
136                pdf_doc->file_path, pdf_doc->occurences);
137#endif
138        docName = new GooString(file_path);
139        doc = new PDFDoc(docName);      // takes ownership of docName
140        pdf_doc->pc++;
141
142        if (!doc->isOk() || !doc->okToPrint()) {
143            switch (fe) {
144            case FE_FAIL:
145                luatex_fail("xpdf: reading PDF image failed");
146                break;
147            case FE_RETURN_NULL:
148                delete doc;
149                // delete docName;
150                if (new_flag == 1) {
151                    if (pdf_doc->file_path != NULL)
152                        free(pdf_doc->file_path);
153                    if (pdf_doc->checksum != NULL)
154                        free(pdf_doc->checksum);
155                    delete pdf_doc;
156                }
157                return (PdfDocument *) NULL;
158                break;
159            default:
160                assert(0);
161            }
162        }
163        pdf_doc->doc = doc;
164    }
165    // PDF file could be opened without problems, checksum ok.
166    if (PdfDocumentTree == NULL)
167        PdfDocumentTree = avl_create(CompPdfDocument, NULL, &avl_xallocator);
168    if ((PdfDocument *) avl_find(PdfDocumentTree, pdf_doc) == NULL) {
169        void **aa = avl_probe(PdfDocumentTree, pdf_doc);
170        assert(aa != NULL);
171    }
172    pdf_doc->occurences++;
173#ifdef DEBUG
174    fprintf(stderr, "\nDEBUG: Incrementing %s (%d)\n",
175            pdf_doc->file_path, pdf_doc->occurences);
176#endif
177    return pdf_doc;
178}
179
180//**********************************************************************
181// AVL sort ObjMap into ObjMapTree by object number and generation
182
183// keep the ObjMap struct small, as these are accumulated until the end
184
185struct ObjMap {
186    Ref in;                     // object num/gen in orig. PDF file
187    int out_num;                // object num after embedding (gen == 0)
188};
189
190static int CompObjMap(const void *pa, const void *pb, void * /*p */ )
191{
192    const Ref *a = &(((const ObjMap *) pa)->in);
193    const Ref *b = &(((const ObjMap *) pb)->in);
194    if (a->num > b->num)
195        return 1;
196    if (a->num < b->num)
197        return -1;
198    if (a->gen == b->gen)       // most likely gen == 0 anyway
199        return 0;
200    if (a->gen < b->gen)
201        return -1;
202    return 1;
203}
204
205static ObjMap *findObjMap(PdfDocument * pdf_doc, Ref in)
206{
207    ObjMap *obj_map, tmp;
208    assert(pdf_doc != NULL);
209    if (pdf_doc->ObjMapTree == NULL)
210        return NULL;
211    tmp.in = in;
212    obj_map = (ObjMap *) avl_find(pdf_doc->ObjMapTree, &tmp);
213    return obj_map;
214}
215
216static void addObjMap(PdfDocument * pdf_doc, Ref in, int out_num)
217{
218    ObjMap *obj_map = NULL;
219    assert(findObjMap(pdf_doc, in) == NULL);
220    if (pdf_doc->ObjMapTree == NULL)
221        pdf_doc->ObjMapTree = avl_create(CompObjMap, NULL, &avl_xallocator);
222    obj_map = new ObjMap;
223    obj_map->in = in;
224    obj_map->out_num = out_num;
225    void **aa = avl_probe(pdf_doc->ObjMapTree, obj_map);
226    assert(aa != NULL);
227}
228
229// When copying the Resources of the selected page, all objects are
230// copied recursively top-down.  The findObjMap() function checks if an
231// object has already been copied; if so, instead of copying just the
232// new object number will be referenced.  The ObjMapTree guarantees,
233// that during the entire LuaTeX run any object from any embedded PDF
234// file will end up max. once in the output PDF file.  Indirect objects
235// are not fetched during copying, but get a new object number from
236// LuaTeX and then will be appended into a linked list.
237
238static int addInObj(PDF pdf, PdfDocument * pdf_doc, Ref ref)
239{
240    ObjMap *obj_map;
241    InObj *p, *q, *n;
242    if (ref.num == 0) {
243        luatex_fail("PDF inclusion: reference to invalid object"
244                    " (is the included pdf broken?)");
245    }
246    if ((obj_map = findObjMap(pdf_doc, ref)) != NULL)
247        return obj_map->out_num;
248    n = new InObj;
249    n->ref = ref;
250    n->next = NULL;
251    n->num = pdf_create_obj(pdf, obj_type_others, 0);
252    addObjMap(pdf_doc, ref, n->num);
253    if (pdf_doc->inObjList == NULL)
254        pdf_doc->inObjList = n;
255    else {
256        // it is important to add new objects at the end of the list,
257        // because new objects are being added while the list is being
258        // written out by writeRefs().
259        for (p = pdf_doc->inObjList; p != NULL; p = p->next)
260            q = p;
261        q->next = n;
262    }
263    return n->num;
264}
265
266//**********************************************************************
267// Function converts double to pdffloat; very small and very large numbers
268// are NOT converted to scientific notation.
269// n must be a number or real conforming to the implementation limits
270// of PDF as specified in appendix C.1 of the PDF Ref.
271// These are:
272// maximum value of ints is +2^32
273// maximum value of reals is +2^15
274// smalles values of reals is 1/(2^16)
275
276static pdffloat conv_double_to_pdffloat(double n)
277{
278    pdffloat a;
279    a.e = 6;
280    a.m = i64round(n * ten_pow[a.e]);
281    return a;
282}
283
284static void copyObject(PDF, PdfDocument *, Object *);
285
286void copyReal(PDF pdf, double d)
287{
288    if (pdf->cave)
289        pdf_out(pdf, ' ');
290    print_pdffloat(pdf, conv_double_to_pdffloat(d));
291    pdf->cave = true;
292}
293
294static void copyString(PDF pdf, GooString * string)
295{
296    char *p;
297    unsigned char c;
298    size_t i, l;
299    p = string->getCString();
300    l = (size_t) string->getLength();
301    if (pdf->cave)
302        pdf_out(pdf, ' ');
303    if (strlen(p) == l) {
304        pdf_out(pdf, '(');
305        for (; *p != 0; p++) {
306            c = (unsigned char) *p;
307            if (c == '(' || c == ')' || c == '\\')
308                pdf_printf(pdf, "\\%c", c);
309            else if (c < 0x20 || c > 0x7F)
310                pdf_printf(pdf, "\\%03o", (int) c);
311            else
312                pdf_out(pdf, c);
313        }
314        pdf_out(pdf, ')');
315    } else {
316        pdf_out(pdf, '<');
317        for (i = 0; i < l; i++) {
318            c = (unsigned char) string->getChar(i);
319            pdf_printf(pdf, "%.2x", (int) c);
320        }
321        pdf_out(pdf, '>');
322    }
323    pdf->cave = true;
324}
325
326static void copyName(PDF pdf, char *s)
327{
328    pdf_out(pdf, '/');
329    for (; *s != 0; s++) {
330        if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' ||
331            *s == '.' || *s == '-' || *s == '+')
332            pdf_out(pdf, *s);
333        else
334            pdf_printf(pdf, "#%.2X", *s & 0xFF);
335    }
336    pdf->cave = true;
337}
338
339static void copyArray(PDF pdf, PdfDocument * pdf_doc, Array * array)
340{
341    int i, l;
342    Object obj1;
343    pdf_begin_array(pdf);
344    for (i = 0, l = array->getLength(); i < l; ++i) {
345        array->getNF(i, &obj1);
346        copyObject(pdf, pdf_doc, &obj1);
347        obj1.free();
348    }
349    pdf_end_array(pdf);
350}
351
352static void copyDict(PDF pdf, PdfDocument * pdf_doc, Dict * dict)
353{
354    int i, l;
355    Object obj1;
356    pdf_begin_dict(pdf);
357    for (i = 0, l = dict->getLength(); i < l; ++i) {
358        copyName(pdf, dict->getKey(i));
359        dict->getValNF(i, &obj1);
360        copyObject(pdf, pdf_doc, &obj1);
361        obj1.free();
362    }
363    pdf_end_dict(pdf);
364}
365
366static void copyStreamStream(PDF pdf, Stream * str)
367{
368    int c, i, len = 1024;
369    str->reset();
370    i = len;
371    while ((c = str->getChar()) != EOF) {
372        if (i == len) {
373            pdf_room(pdf, len);
374            i = 0;
375        }
376        pdf_quick_out(pdf, c);
377        i++;
378    }
379}
380
381static void copyStream(PDF pdf, PdfDocument * pdf_doc, Stream * stream)
382{
383    copyDict(pdf, pdf_doc, stream->getDict());
384    pdf_begin_stream(pdf);
385    assert(pdf->zip_write_state == NO_ZIP);
386    copyStreamStream(pdf, stream->getUndecodedStream());
387    pdf_end_stream(pdf);
388}
389
390static void copyObject(PDF pdf, PdfDocument * pdf_doc, Object * obj)
391{
392    switch (obj->getType()) {
393    case objBool:
394        pdf_add_bool(pdf, (int) obj->getBool());
395        break;
396    case objInt:
397        pdf_add_int(pdf, obj->getInt());
398        break;
399    case objReal:
400        copyReal(pdf, obj->getReal());
401        break;
402        // not needed:
403        // case objNum:
404        // GBool isNum() { return type == objInt || type == objReal; }
405    case objString:
406        copyString(pdf, obj->getString());
407        break;
408    case objName:
409        copyName(pdf, obj->getName());
410        break;
411    case objNull:
412        pdf_add_null(pdf);
413        break;
414    case objArray:
415        copyArray(pdf, pdf_doc, obj->getArray());
416        break;
417    case objDict:
418        copyDict(pdf, pdf_doc, obj->getDict());
419        break;
420    case objStream:
421        copyStream(pdf, pdf_doc, obj->getStream());
422        break;
423    case objRef:
424        pdf_add_ref(pdf, addInObj(pdf, pdf_doc, obj->getRef()));
425        break;
426    case objCmd:
427    case objError:
428    case objEOF:
429    case objNone:
430        luatex_fail("PDF inclusion: type <%s> cannot be copied",
431                    obj->getTypeName());
432        break;
433    default:
434        assert(0);              // xpdf doesn't have any other types
435    }
436}
437
438//**********************************************************************
439
440static void writeRefs(PDF pdf, PdfDocument * pdf_doc)
441{
442    InObj *r, *n;
443    Object obj1;
444    XRef *xref;
445    PDFDoc *doc = pdf_doc->doc;
446    xref = doc->getXRef();
447    for (r = pdf_doc->inObjList; r != NULL;) {
448        xref->fetch(r->ref.num, r->ref.gen, &obj1);
449        if (obj1.isStream())
450            pdf_begin_obj(pdf, r->num, OBJSTM_NEVER);
451        else
452            pdf_begin_obj(pdf, r->num, 2);      // \pdfobjcompresslevel = 2 is for this
453        copyObject(pdf, pdf_doc, &obj1);
454        obj1.free();
455        pdf_end_obj(pdf);
456        n = r->next;
457        delete r;
458        pdf_doc->inObjList = r = n;
459    }
460}
461
462// get the pagebox coordinates according to the pagebox_spec
463
464static PDFRectangle *get_pagebox(Page * page, int pagebox_spec)
465{
466    switch (pagebox_spec) {
467    case PDF_BOX_SPEC_MEDIA:
468        return page->getMediaBox();
469        break;
470    case PDF_BOX_SPEC_CROP:
471        return page->getCropBox();
472        break;
473    case PDF_BOX_SPEC_BLEED:
474        return page->getBleedBox();
475        break;
476    case PDF_BOX_SPEC_TRIM:
477        return page->getTrimBox();
478        break;
479    case PDF_BOX_SPEC_ART:
480        return page->getArtBox();
481        break;
482    default:
483        luatex_fail("PDF inclusion: unknown value of pagebox spec (%i)",
484                    (int) pagebox_spec);
485    }
486    return page->getMediaBox(); // to make the compiler happy
487}
488
489// Reads various information about the PDF and sets it up for later inclusion.
490// This will fail if the PDF version of the PDF is higher than
491// minor_pdf_version_wanted or page_name is given and can not be found.
492// It makes no sense to give page_name _and_ page_num.
493// Returns the page number.
494
495void
496read_pdf_info(image_dict * idict, int minor_pdf_version_wanted,
497              int pdf_inclusion_errorlevel, img_readtype_e readtype)
498{
499    PdfDocument *pdf_doc;
500    PDFDoc *doc;
501    Catalog *catalog;
502    Page *page;
503    int rotate;
504    PDFRectangle *pagebox;
505    int pdf_major_version_found, pdf_minor_version_found;
506    float xsize, ysize, xorig, yorig;
507    assert(idict != NULL);
508    assert(img_type(idict) == IMG_TYPE_PDF);
509    assert(readtype == IMG_CLOSEINBETWEEN);     // only this is implemented
510    // initialize
511    if (isInit == gFalse) {
512        globalParams = new GlobalParams();
513        globalParams->setErrQuiet(gFalse);
514        isInit = gTrue;
515    }
516    // open PDF file
517    pdf_doc = refPdfDocument(img_filepath(idict), FE_FAIL);
518    doc = pdf_doc->doc;
519    catalog = doc->getCatalog();
520    // check PDF version
521    // this works only for PDF 1.x -- but since any versions of PDF newer
522    // than 1.x will not be backwards compatible to PDF 1.x, pdfTeX will
523    // then have to changed drastically anyway.
524    pdf_major_version_found = doc->getPDFMajorVersion();
525    pdf_minor_version_found = doc->getPDFMinorVersion();
526    if ((pdf_major_version_found > 1)
527        || (pdf_minor_version_found > minor_pdf_version_wanted)) {
528        const char *msg =
529            "PDF inclusion: found PDF version <%d.%d>, but at most version <1.%d> allowed";
530        if (pdf_inclusion_errorlevel > 0) {
531            luatex_fail(msg, pdf_major_version_found, pdf_minor_version_found,
532                        minor_pdf_version_wanted);
533        } else {
534            luatex_warn(msg, pdf_major_version_found, pdf_minor_version_found,
535                        minor_pdf_version_wanted);
536        }
537    }
538    img_totalpages(idict) = catalog->getNumPages();
539    if (img_pagename(idict)) {
540        // get page by name
541        GooString name(img_pagename(idict));
542        LinkDest *link = doc->findDest(&name);
543        if (link == NULL || !link->isOk())
544            luatex_fail("PDF inclusion: invalid destination <%s>",
545                        img_pagename(idict));
546        Ref ref = link->getPageRef();
547        img_pagenum(idict) = catalog->findPage(ref.num, ref.gen);
548        if (img_pagenum(idict) == 0)
549            luatex_fail("PDF inclusion: destination is not a page <%s>",
550                        img_pagename(idict));
551        delete link;
552    } else {
553        // get page by number
554        if (img_pagenum(idict) <= 0
555            || img_pagenum(idict) > img_totalpages(idict))
556            luatex_fail("PDF inclusion: required page <%i> does not exist",
557                        (int) img_pagenum(idict));
558    }
559    // get the required page
560    page = catalog->getPage(img_pagenum(idict));
561
562    // get the pagebox coordinates (media, crop,...) to use.
563    pagebox = get_pagebox(page, img_pagebox(idict));
564    if (pagebox->x2 > pagebox->x1) {
565        xorig = pagebox->x1;
566        xsize = pagebox->x2 - pagebox->x1;
567    } else {
568        xorig = pagebox->x2;
569        xsize = pagebox->x1 - pagebox->x2;
570    }
571    if (pagebox->y2 > pagebox->y1) {
572        yorig = pagebox->y1;
573        ysize = pagebox->y2 - pagebox->y1;
574    } else {
575        yorig = pagebox->y2;
576        ysize = pagebox->y1 - pagebox->y2;
577    }
578    // The following 4 parameters are raw. Do _not_ modify by /Rotate!
579    img_xsize(idict) = bp2sp(xsize);
580    img_ysize(idict) = bp2sp(ysize);
581    img_xorig(idict) = bp2sp(xorig);
582    img_yorig(idict) = bp2sp(yorig);
583
584    // Handle /Rotate parameter. Only multiples of 90 deg. are allowed
585    // (PDF Ref. v1.3, p. 78).
586    rotate = page->getRotate();
587    switch (((rotate % 360) + 360) % 360) {     // handles also neg. angles
588    case 0:
589        img_rotation(idict) = 0;
590        break;
591    case 90:
592        img_rotation(idict) = 3;        // PDF counts clockwise!
593        break;
594    case 180:
595        img_rotation(idict) = 2;
596        break;
597    case 270:
598        img_rotation(idict) = 1;
599        break;
600    default:
601        luatex_warn
602            ("PDF inclusion: "
603             "/Rotate parameter in PDF file not multiple of 90 degrees.");
604    }
605
606    // currently unused info whether PDF contains a /Group
607    if (page->getGroup() != NULL)
608        img_set_group(idict);
609
610    if (readtype == IMG_CLOSEINBETWEEN)
611        unrefPdfDocument(img_filepath(idict));
612}
613
614//**********************************************************************
615// Writes the current epf_doc.
616// Here the included PDF is copied, so most errors that can happen
617// during PDF inclusion will arise here.
618
619void write_epdf(PDF pdf, image_dict * idict)
620{
621    PdfDocument *pdf_doc;
622    PDFDoc *doc;
623    Catalog *catalog;
624    Page *page;
625    Ref *pageref;
626    Dict *pageDict;
627    Object obj1, contents, pageobj, pagesobj1, pagesobj2, *op1, *op2, *optmp;
628    PDFRectangle *pagebox;
629    int i, l;
630    double bbox[4];
631    char s[256];
632    const char *pagedictkeys[] =
633        { "Group", "LastModified", "Metadata", "PieceInfo", "Resources",
634        "SeparationInfo", NULL
635    };
636    assert(idict != NULL);
637
638    // open PDF file
639    pdf_doc = refPdfDocument(img_filepath(idict), FE_FAIL);
640    doc = pdf_doc->doc;
641    catalog = doc->getCatalog();
642    page = catalog->getPage(img_pagenum(idict));
643    pageref = catalog->getPageRef(img_pagenum(idict));
644    assert(pageref != NULL);    // was checked already in read_pdf_info()
645    doc->getXRef()->fetch(pageref->num, pageref->gen, &pageobj);
646    pageDict = pageobj.getDict();
647
648    // write the Page header
649    pdf_begin_obj(pdf, img_objnum(idict), OBJSTM_NEVER);
650    pdf_begin_dict(pdf);
651    pdf_dict_add_name(pdf, "Type", "XObject");
652    pdf_dict_add_name(pdf, "Subtype", "Form");
653
654    if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0)
655        pdf_printf(pdf, "\n%s\n", img_attr(idict));
656    pdf_dict_add_int(pdf, "FormType", 1);
657
658    // write additional information
659    pdf_dict_add_img_filename(pdf, idict);
660    snprintf(s, 30, "%s.PageNumber", pdfkeyprefix);
661    pdf_dict_add_int(pdf, s, (int) img_pagenum(idict));
662    doc->getDocInfoNF(&obj1);
663    if (obj1.isRef()) {
664        // the info dict must be indirect (PDF Ref p. 61)
665        snprintf(s, 30, "%s.InfoDict", pdfkeyprefix);
666        pdf_dict_add_ref(pdf, s, addInObj(pdf, pdf_doc, obj1.getRef()));
667    }
668    obj1.free();
669    if (img_is_bbox(idict)) {
670        bbox[0] = sp2bp(img_bbox(idict)[0]);
671        bbox[1] = sp2bp(img_bbox(idict)[1]);
672        bbox[2] = sp2bp(img_bbox(idict)[2]);
673        bbox[3] = sp2bp(img_bbox(idict)[3]);
674    } else {
675        // get the pagebox coordinates (media, crop,...) to use.
676        pagebox = get_pagebox(page, img_pagebox(idict));
677        bbox[0] = pagebox->x1;
678        bbox[1] = pagebox->y1;
679        bbox[2] = pagebox->x2;
680        bbox[3] = pagebox->y2;
681    }
682    pdf_add_name(pdf, "BBox");
683    pdf_begin_array(pdf);
684    copyReal(pdf, bbox[0]);
685    copyReal(pdf, bbox[1]);
686    copyReal(pdf, bbox[2]);
687    copyReal(pdf, bbox[3]);
688    pdf_end_array(pdf);
689    // The /Matrix calculation is replaced by transforms in out_img().
690
691    // Now all relevant parts of the Page dictionary are copied:
692
693    // Metadata validity check (as a stream it must be indirect)
694    pageDict->lookupNF((char *) "Metadata", &obj1);
695    if (!obj1.isNull() && !obj1.isRef())
696        luatex_warn("PDF inclusion: /Metadata must be indirect object");
697    obj1.free();
698
699    // copy selected items in Page dictionary
700    for (i = 0; pagedictkeys[i] != NULL; i++) {
701        pageDict->lookupNF((char *) pagedictkeys[i], &obj1);
702        if (!obj1.isNull()) {
703            pdf_add_name(pdf, pagedictkeys[i]);
704            copyObject(pdf, pdf_doc, &obj1);    // preserves indirection
705        }
706        obj1.free();
707    }
708
709    // If there are no Resources in the Page dict of the embedded page,
710    // try to inherit the Resources from the Pages tree of the embedded
711    // PDF file, climbing up the tree until the Resources are found.
712    // (This fixes a problem with Scribus 1.3.3.14.)
713    pageDict->lookupNF((char *) "Resources", &obj1);
714    if (obj1.isNull()) {
715        op1 = &pagesobj1;
716        op2 = &pagesobj2;
717        pageDict->lookup((char *) "Parent", op1);
718        while (op1->isDict()) {
719            obj1.free();
720            op1->dictLookupNF((char *) "Resources", &obj1);
721            if (!obj1.isNull()) {
722                pdf_add_name(pdf, (const char *) "Resources");
723                copyObject(pdf, pdf_doc, &obj1);
724                break;
725            }
726            op1->dictLookup((char *) "Parent", op2);
727            optmp = op1;
728            op1 = op2;
729            op2 = optmp;
730            op2->free();
731        };
732        if (!op1->isDict())
733            luatex_warn("PDF inclusion: Page /Resources missing.");
734        op1->free();
735    }
736    obj1.free();
737
738    // write the Page contents
739    page->getContents(&contents);
740    if (contents.isStream()) {
741        // Variant A: get stream and recompress under control
742        // of \pdfcompresslevel
743        //
744        // pdf_begin_stream();
745        // copyStreamStream(contents->getStream());
746        // pdf_end_stream();
747
748        // Variant B: copy stream without recompressing
749        //
750        contents.streamGetDict()->lookup((char *) "F", &obj1);
751        if (!obj1.isNull()) {
752            luatex_fail("PDF inclusion: Unsupported external stream");
753        }
754        obj1.free();
755        contents.streamGetDict()->lookup((char *) "Length", &obj1);
756        assert(!obj1.isNull());
757        pdf_add_name(pdf, (const char *) "Length");
758        copyObject(pdf, pdf_doc, &obj1);
759        obj1.free();
760        contents.streamGetDict()->lookup((char *) "Filter", &obj1);
761        if (!obj1.isNull()) {
762            pdf_add_name(pdf, (const char *) "Filter");
763            copyObject(pdf, pdf_doc, &obj1);
764            obj1.free();
765            contents.streamGetDict()->lookup((char *) "DecodeParms", &obj1);
766            if (!obj1.isNull()) {
767                pdf_add_name(pdf, (const char *) "DecodeParms");
768                copyObject(pdf, pdf_doc, &obj1);
769            }
770        }
771        obj1.free();
772        pdf_end_dict(pdf);
773        pdf_begin_stream(pdf);
774        copyStreamStream(pdf, contents.getStream()->getUndecodedStream());
775        pdf_end_stream(pdf);
776        pdf_end_obj(pdf);
777    } else if (contents.isArray()) {
778        pdf_dict_add_streaminfo(pdf);
779        pdf_end_dict(pdf);
780        pdf_begin_stream(pdf);
781        for (i = 0, l = contents.arrayGetLength(); i < l; ++i) {
782            copyStreamStream(pdf, (contents.arrayGet(i, &obj1))->getStream());
783            obj1.free();
784            if (i < (l - 1)) {
785                // put a space between streams to be on the safe side (streams
786                // should have a trailing space here, but one never knows)
787                pdf_out(pdf, ' ');
788            }
789        }
790        pdf_end_stream(pdf);
791        pdf_end_obj(pdf);
792    } else {                    // the contents are optional, but we need to include an empty stream
793        pdf_dict_add_streaminfo(pdf);
794        pdf_end_dict(pdf);
795        pdf_begin_stream(pdf);
796        pdf_end_stream(pdf);
797        pdf_end_obj(pdf);
798    }
799    // write out all indirect objects
800    writeRefs(pdf, pdf_doc);
801    contents.free();
802    pageobj.free();
803    // unrefPdfDocument() must come after contents.free() and pageobj.free()!
804    // TH: The next line makes repeated pdf inclusion unacceptably slow
805#if 0
806    unrefPdfDocument(img_filepath(idict));
807#endif
808}
809
810//**********************************************************************
811// Deallocate a PdfDocument with all its resources
812
813static void deletePdfDocumentPdfDoc(PdfDocument * pdf_doc)
814{
815    InObj *r, *n;
816    assert(pdf_doc != NULL);
817    // this may be probably needed for an emergency destroyPdfDocument()
818    for (r = pdf_doc->inObjList; r != NULL; r = n) {
819        n = r->next;
820        delete r;
821    }
822#ifdef DEBUG
823    fprintf(stderr, "\nDEBUG: Deleting PDFDoc %s\n", pdf_doc->file_path);
824#endif
825    delete pdf_doc->doc;
826    pdf_doc->doc = NULL;
827    pdf_doc->pc++;
828}
829
830static void destroyPdfDocument(void *pa, void * /*pb */ )
831{
832    PdfDocument *pdf_doc = (PdfDocument *) pa;
833    deletePdfDocumentPdfDoc(pdf_doc);
834    // TODO: delete rest of pdf_doc
835}
836
837// Called when an image has been written and its resources in image_tab are
838// freed and it's not referenced anymore.
839
840void unrefPdfDocument(char *file_path)
841{
842    PdfDocument *pdf_doc = findPdfDocument(file_path);
843    assert(pdf_doc != NULL);
844    assert(pdf_doc->occurences != 0);   // aim for point landing
845    pdf_doc->occurences--;
846#ifdef DEBUG
847    fprintf(stderr, "\nDEBUG: Decrementing %s (%d)\n",
848            pdf_doc->file_path, pdf_doc->occurences);
849#endif
850    if (pdf_doc->occurences == 0) {
851        assert(pdf_doc->inObjList == NULL);     // should be eaten up already
852        deletePdfDocumentPdfDoc(pdf_doc);
853    }
854}
855
856// Called when PDF embedding system is finalized.
857// Now deallocate all remaining PdfDocuments.
858
859void epdf_free()
860{
861    if (PdfDocumentTree != NULL)
862        avl_destroy(PdfDocumentTree, destroyPdfDocument);
863    PdfDocumentTree = NULL;
864    if (isInit == gTrue)
865        delete globalParams;
866    isInit = gFalse;
867}
868