1<?php
2/**
3 * This file is part of FPDI
4 *
5 * @package   setasign\Fpdi
6 * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
7 * @license   http://opensource.org/licenses/mit-license The MIT License
8 */
9
10namespace setasign\Fpdi;
11
12use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
13use setasign\Fpdi\PdfParser\PdfParserException;
14use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
15use setasign\Fpdi\PdfParser\Type\PdfNull;
16
17/**
18 * Class Fpdi
19 *
20 * This class let you import pages of existing PDF documents into a reusable structure for FPDF.
21 *
22 * @package setasign\Fpdi
23 */
24class Fpdi extends FpdfTpl
25{
26    use FpdiTrait;
27
28    /**
29     * FPDI version
30     *
31     * @string
32     */
33    const VERSION = '2.3.1';
34
35    protected function _enddoc()
36    {
37        parent::_enddoc();
38        $this->cleanUp();
39    }
40
41    /**
42     * Draws an imported page or a template onto the page or another template.
43     *
44     * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
45     * aspect ratio.
46     *
47     * @param mixed $tpl The template id
48     * @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array
49     *                           with the keys "x", "y", "width", "height", "adjustPageSize".
50     * @param float|int $y The ordinate of upper-left corner.
51     * @param float|int|null $width The width.
52     * @param float|int|null $height The height.
53     * @param bool $adjustPageSize
54     * @return array The size
55     * @see Fpdi::getTemplateSize()
56     */
57    public function useTemplate($tpl, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false)
58    {
59        if (isset($this->importedPages[$tpl])) {
60            $size = $this->useImportedPage($tpl, $x, $y, $width, $height, $adjustPageSize);
61            if ($this->currentTemplateId !== null) {
62                $this->templates[$this->currentTemplateId]['resources']['templates']['importedPages'][$tpl] = $tpl;
63            }
64            return $size;
65        }
66
67        return parent::useTemplate($tpl, $x, $y, $width, $height, $adjustPageSize);
68    }
69
70    /**
71     * Get the size of an imported page or template.
72     *
73     * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
74     * aspect ratio.
75     *
76     * @param mixed $tpl The template id
77     * @param float|int|null $width The width.
78     * @param float|int|null $height The height.
79     * @return array|bool An array with following keys: width, height, 0 (=width), 1 (=height), orientation (L or P)
80     */
81    public function getTemplateSize($tpl, $width = null, $height = null)
82    {
83        $size = parent::getTemplateSize($tpl, $width, $height);
84        if ($size === false) {
85            return $this->getImportedPageSize($tpl, $width, $height);
86        }
87
88        return $size;
89    }
90
91    /**
92     * @inheritdoc
93     * @throws CrossReferenceException
94     * @throws PdfParserException
95     */
96    protected function _putimages()
97    {
98        $this->currentReaderId = null;
99        parent::_putimages();
100
101        foreach ($this->importedPages as $key => $pageData) {
102            $this->_newobj();
103            $this->importedPages[$key]['objectNumber'] = $this->n;
104            $this->currentReaderId = $pageData['readerId'];
105            $this->writePdfType($pageData['stream']);
106            $this->_put('endobj');
107        }
108
109        foreach (\array_keys($this->readers) as $readerId) {
110            $parser = $this->getPdfReader($readerId)->getParser();
111            $this->currentReaderId = $readerId;
112
113            while (($objectNumber = \array_pop($this->objectsToCopy[$readerId])) !== null) {
114                try {
115                    $object = $parser->getIndirectObject($objectNumber);
116
117                } catch (CrossReferenceException $e) {
118                    if ($e->getCode() === CrossReferenceException::OBJECT_NOT_FOUND) {
119                        $object = PdfIndirectObject::create($objectNumber, 0, new PdfNull());
120                    } else {
121                        throw $e;
122                    }
123                }
124
125                $this->writePdfType($object);
126            }
127        }
128
129        $this->currentReaderId = null;
130    }
131
132    /**
133     * @inheritdoc
134     */
135    protected function _putxobjectdict()
136    {
137        foreach ($this->importedPages as $key => $pageData) {
138            $this->_put('/' . $pageData['id'] . ' ' . $pageData['objectNumber'] . ' 0 R');
139        }
140
141        parent::_putxobjectdict();
142    }
143
144    /**
145     * @inheritdoc
146     */
147    protected function _put($s, $newLine = true)
148    {
149        if ($newLine) {
150            $this->buffer .= $s . "\n";
151        } else {
152            $this->buffer .= $s;
153        }
154    }
155}
156