summaryrefslogtreecommitdiffstats
path: root/vendor/setasign
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-14 13:26:02 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-14 13:26:02 +0000
commitfcbf3ce37ca8f90a3e36d524a3274ffc063a40e3 (patch)
tree84c735df2e97350a721273e9dd425729d43cc8a2 /vendor/setasign
parentInitial commit. (diff)
downloadicingaweb2-module-pdfexport-fcbf3ce37ca8f90a3e36d524a3274ffc063a40e3.tar.xz
icingaweb2-module-pdfexport-fcbf3ce37ca8f90a3e36d524a3274ffc063a40e3.zip
Adding upstream version 0.10.2+dfsg1.upstream/0.10.2+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/setasign')
-rw-r--r--vendor/setasign/fpdi/LICENSE.txt21
-rw-r--r--vendor/setasign/fpdi/README.md131
-rw-r--r--vendor/setasign/fpdi/SECURITY.md5
-rw-r--r--vendor/setasign/fpdi/composer.json51
-rw-r--r--vendor/setasign/fpdi/src/FpdfTpl.php21
-rw-r--r--vendor/setasign/fpdi/src/FpdfTplTrait.php470
-rw-r--r--vendor/setasign/fpdi/src/Fpdi.php153
-rw-r--r--vendor/setasign/fpdi/src/FpdiException.php18
-rw-r--r--vendor/setasign/fpdi/src/FpdiTrait.php559
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/CrossReference/AbstractReader.php95
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/CrossReference/CrossReference.php326
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/CrossReference/CrossReferenceException.php79
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/CrossReference/FixedReader.php199
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/CrossReference/LineReader.php167
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/CrossReference/ReaderInterface.php34
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Filter/Ascii85.php102
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Filter/Ascii85Exception.php27
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Filter/AsciiHex.php47
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Filter/FilterException.php23
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Filter/FilterInterface.php25
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Filter/Flate.php86
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Filter/FlateException.php27
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Filter/Lzw.php187
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Filter/LzwException.php22
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/PdfParser.php381
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/PdfParserException.php49
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/StreamReader.php471
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Tokenizer.php154
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfArray.php85
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfBoolean.php42
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfDictionary.php134
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfHexString.php77
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfIndirectObject.php103
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfIndirectObjectReference.php52
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfName.php82
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfNull.php19
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfNumeric.php43
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfStream.php326
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfString.php172
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfToken.php43
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfType.php78
-rw-r--r--vendor/setasign/fpdi/src/PdfParser/Type/PdfTypeException.php24
-rw-r--r--vendor/setasign/fpdi/src/PdfReader/DataStructure/Rectangle.php173
-rw-r--r--vendor/setasign/fpdi/src/PdfReader/Page.php271
-rw-r--r--vendor/setasign/fpdi/src/PdfReader/PageBoundaries.php94
-rw-r--r--vendor/setasign/fpdi/src/PdfReader/PdfReader.php234
-rw-r--r--vendor/setasign/fpdi/src/PdfReader/PdfReaderException.php34
-rw-r--r--vendor/setasign/fpdi/src/Tcpdf/Fpdi.php270
-rw-r--r--vendor/setasign/fpdi/src/TcpdfFpdi.php23
-rw-r--r--vendor/setasign/fpdi/src/Tfpdf/FpdfTpl.php23
-rw-r--r--vendor/setasign/fpdi/src/Tfpdf/Fpdi.php154
-rw-r--r--vendor/setasign/fpdi/src/autoload.php21
52 files changed, 6507 insertions, 0 deletions
diff --git a/vendor/setasign/fpdi/LICENSE.txt b/vendor/setasign/fpdi/LICENSE.txt
new file mode 100644
index 0000000..45672fa
--- /dev/null
+++ b/vendor/setasign/fpdi/LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2020 Setasign GmbH & Co. KG, https://www.setasign.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. \ No newline at end of file
diff --git a/vendor/setasign/fpdi/README.md b/vendor/setasign/fpdi/README.md
new file mode 100644
index 0000000..c503b7d
--- /dev/null
+++ b/vendor/setasign/fpdi/README.md
@@ -0,0 +1,131 @@
+FPDI - Free PDF Document Importer
+=================================
+
+[![Latest Stable Version](https://poser.pugx.org/setasign/fpdi/v/stable.svg)](https://packagist.org/packages/setasign/fpdi)
+[![Total Downloads](https://poser.pugx.org/setasign/fpdi/downloads.svg)](https://packagist.org/packages/setasign/fpdi)
+[![Latest Unstable Version](https://poser.pugx.org/setasign/fpdi/v/unstable.svg)](https://packagist.org/packages/setasign/fpdi)
+[![License](https://poser.pugx.org/setasign/fpdi/license.svg)](https://packagist.org/packages/setasign/fpdi)
+
+:heavy_exclamation_mark: This document refers to FPDI 2. Version 1 is deprecated and development is discontinued. :heavy_exclamation_mark:
+
+FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF
+documents and use them as templates in [FPDF](http://www.fpdf.org), which was developed by Olivier Plathey. Apart
+from a copy of [FPDF](http://www.fpdf.org), FPDI does not require any special PHP extensions.
+
+FPDI can also be used as an extension for [TCPDF](https://github.com/tecnickcom/TCPDF) or
+[tFPDF](http://fpdf.org/en/script/script92.php), too.
+
+## Installation with [Composer](https://packagist.org/packages/setasign/fpdi)
+
+Because FPDI can be used with FPDF, TCPDF or tFPDF we haven't added a fixed dependency in the main
+composer.json file. You need to add the dependency to the PDF generation library of your choice
+yourself.
+
+To use FPDI with FPDF include following in your composer.json file:
+
+```json
+{
+ "require": {
+ "setasign/fpdf": "1.8.*",
+ "setasign/fpdi": "^2.0"
+ }
+}
+```
+
+If you want to use TCPDF, you have to update your composer.json to:
+
+```json
+{
+ "require": {
+ "tecnickcom/tcpdf": "6.3.*",
+ "setasign/fpdi": "^2.0"
+ }
+}
+```
+
+If you want to use tFPDF, you have to update your composer.json to:
+
+```json
+{
+ "require": {
+ "setasign/tfpdf": "1.31.*",
+ "setasign/fpdi": "^2.3"
+ }
+}
+```
+
+## Manual Installation
+
+If you do not use composer, just require the autoload.php in the /src folder:
+
+```php
+require_once('src/autoload.php');
+```
+
+If you have a PSR-4 autoloader implemented, just register the src path as follows:
+```php
+$loader = new \Example\Psr4AutoloaderClass;
+$loader->register();
+$loader->addNamespace('setasign\Fpdi', 'path/to/src/');
+```
+
+## Changes to Version 1
+
+Version 2 is a complete rewrite from scratch of FPDI which comes with:
+- Namespaced code
+- Clean and up-to-date code base and style
+- PSR-4 compatible autoloading
+- Performance improvements by up to 100%
+- Less memory consumption
+- Native support for reading PDFs from strings or stream-resources
+- Support for documents with "invalid" data before their file-header
+- Optimized page tree resolving
+- Usage of individual exceptions
+- Several test types (unit, functional and visual tests)
+
+We tried to keep the main methods and logical workflow the same as in version 1 but please
+notice that there were incompatible changes which you should consider when updating to
+version 2:
+- You need to load the code using the `src/autoload.php` file instead of `classes/FPDI.php`.
+- The classes and traits are namespaced now: `setasign\Fpdi`
+- Page boundaries beginning with a slash, such as `/MediaBox`, are not supported anymore. Remove
+ the slash or use a constant of `PdfReader\PageBoundaries`.
+- The parameters $x, $y, $width and $height of the `useTemplate()` or `getTemplateSize()`
+ method have more logical correct default values now. Passing `0` as width or height will
+ result in an `InvalidArgumentException` now.
+- The return value of `getTemplateSize()` had changed to an array with more speaking keys
+ and reusability: Use `width` instead of `w` and `height` instead of `h`.
+- If you want to use **FPDI with TCPDF** you need to refactor your code to use the class `Tcpdf\Fpdi`
+(since 2.1; before it was `TcpdfFpdi`) instead of `FPDI`.
+
+## Example and Documentation
+
+A simple example, that imports a single page and places this onto a new created page:
+
+```php
+<?php
+use setasign\Fpdi\Fpdi;
+// or for usage with TCPDF:
+// use setasign\Fpdi\Tcpdf\Fpdi;
+
+// or for usage with tFPDF:
+// use setasign\Fpdi\Tfpdf\Fpdi;
+
+// setup the autoload function
+require_once('vendor/autoload.php');
+
+// initiate FPDI
+$pdf = new Fpdi();
+// add a page
+$pdf->AddPage();
+// set the source file
+$pdf->setSourceFile("Fantastic-Speaker.pdf");
+// import page 1
+$tplId = $pdf->importPage(1);
+// use the imported page and place it at point 10,10 with a width of 100 mm
+$pdf->useTemplate($tplId, 10, 10, 100);
+
+$pdf->Output();
+```
+
+A full end-user documentation and API reference is available [here](https://manuals.setasign.com/fpdi-manual/).
diff --git a/vendor/setasign/fpdi/SECURITY.md b/vendor/setasign/fpdi/SECURITY.md
new file mode 100644
index 0000000..da9c516
--- /dev/null
+++ b/vendor/setasign/fpdi/SECURITY.md
@@ -0,0 +1,5 @@
+## Security contact information
+
+To report a security vulnerability, please use the
+[Tidelift security contact](https://tidelift.com/security).
+Tidelift will coordinate the fix and disclosure.
diff --git a/vendor/setasign/fpdi/composer.json b/vendor/setasign/fpdi/composer.json
new file mode 100644
index 0000000..da67012
--- /dev/null
+++ b/vendor/setasign/fpdi/composer.json
@@ -0,0 +1,51 @@
+{
+ "name": "setasign/fpdi",
+ "homepage": "https://www.setasign.com/fpdi",
+ "description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.",
+ "type": "library",
+ "keywords": [
+ "pdf",
+ "fpdi",
+ "fpdf"
+ ],
+ "license": "MIT",
+ "autoload": {
+ "psr-4": {
+ "setasign\\Fpdi\\": "src/"
+ }
+ },
+ "require": {
+ "php": "^5.6 || ^7.0 || ^8.0",
+ "ext-zlib": "*"
+ },
+ "conflict": {
+ "setasign/tfpdf": "<1.31"
+ },
+ "authors": [
+ {
+ "name": "Jan Slabon",
+ "email": "jan.slabon@setasign.com",
+ "homepage": "https://www.setasign.com"
+ },
+ {
+ "name": "Maximilian Kresse",
+ "email": "maximilian.kresse@setasign.com",
+ "homepage": "https://www.setasign.com"
+ }
+ ],
+ "suggest": {
+ "setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured."
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~5.7",
+ "setasign/fpdf": "~1.8",
+ "tecnickcom/tcpdf": "~6.2",
+ "setasign/tfpdf": "1.31",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "setasign\\Fpdi\\": "tests/"
+ }
+ }
+}
diff --git a/vendor/setasign/fpdi/src/FpdfTpl.php b/vendor/setasign/fpdi/src/FpdfTpl.php
new file mode 100644
index 0000000..4b93f53
--- /dev/null
+++ b/vendor/setasign/fpdi/src/FpdfTpl.php
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi;
+
+/**
+ * Class FpdfTpl
+ *
+ * This class adds a templating feature to FPDF.
+ */
+class FpdfTpl extends \FPDF
+{
+ use FpdfTplTrait;
+}
diff --git a/vendor/setasign/fpdi/src/FpdfTplTrait.php b/vendor/setasign/fpdi/src/FpdfTplTrait.php
new file mode 100644
index 0000000..d2da97c
--- /dev/null
+++ b/vendor/setasign/fpdi/src/FpdfTplTrait.php
@@ -0,0 +1,470 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi;
+
+/**
+ * Trait FpdfTplTrait
+ *
+ * This class adds a templating feature to tFPDF.
+ */
+trait FpdfTplTrait
+{
+ /**
+ * Data of all created templates.
+ *
+ * @var array
+ */
+ protected $templates = [];
+
+ /**
+ * The template id for the currently created template.
+ *
+ * @var null|int
+ */
+ protected $currentTemplateId;
+
+ /**
+ * A counter for template ids.
+ *
+ * @var int
+ */
+ protected $templateId = 0;
+
+ /**
+ * Set the page format of the current page.
+ *
+ * @param array $size An array with two values defining the size.
+ * @param string $orientation "L" for landscape, "P" for portrait.
+ * @throws \BadMethodCallException
+ */
+ public function setPageFormat($size, $orientation)
+ {
+ if ($this->currentTemplateId !== null) {
+ throw new \BadMethodCallException('The page format cannot be changed when writing to a template.');
+ }
+
+ if (!\in_array($orientation, ['P', 'L'], true)) {
+ throw new \InvalidArgumentException(\sprintf(
+ 'Invalid page orientation "%s"! Only "P" and "L" are allowed!',
+ $orientation
+ ));
+ }
+
+ $size = $this->_getpagesize($size);
+
+ if (
+ $orientation != $this->CurOrientation
+ || $size[0] != $this->CurPageSize[0]
+ || $size[1] != $this->CurPageSize[1]
+ ) {
+ // New size or orientation
+ if ($orientation === 'P') {
+ $this->w = $size[0];
+ $this->h = $size[1];
+ } else {
+ $this->w = $size[1];
+ $this->h = $size[0];
+ }
+ $this->wPt = $this->w * $this->k;
+ $this->hPt = $this->h * $this->k;
+ $this->PageBreakTrigger = $this->h - $this->bMargin;
+ $this->CurOrientation = $orientation;
+ $this->CurPageSize = $size;
+
+ $this->PageInfo[$this->page]['size'] = array($this->wPt, $this->hPt);
+ }
+ }
+
+ /**
+ * Draws a template onto the page or another template.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $tpl The template id
+ * @param array|float|int $x The abscissa of upper-left corner. Alternatively you could use an assoc array
+ * with the keys "x", "y", "width", "height", "adjustPageSize".
+ * @param float|int $y The ordinate of upper-left corner.
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @param bool $adjustPageSize
+ * @return array The size
+ * @see FpdfTplTrait::getTemplateSize()
+ */
+ public function useTemplate($tpl, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false)
+ {
+ if (!isset($this->templates[$tpl])) {
+ throw new \InvalidArgumentException('Template does not exist!');
+ }
+
+ if (\is_array($x)) {
+ unset($x['tpl']);
+ \extract($x, EXTR_IF_EXISTS);
+ /** @noinspection NotOptimalIfConditionsInspection */
+ /** @noinspection PhpConditionAlreadyCheckedInspection */
+ if (\is_array($x)) {
+ $x = 0;
+ }
+ }
+
+ $template = $this->templates[$tpl];
+
+ $originalSize = $this->getTemplateSize($tpl);
+ $newSize = $this->getTemplateSize($tpl, $width, $height);
+ if ($adjustPageSize) {
+ $this->setPageFormat($newSize, $newSize['orientation']);
+ }
+
+ $this->_out(
+ // reset standard values, translate and scale
+ \sprintf(
+ 'q 0 J 1 w 0 j 0 G 0 g %.4F 0 0 %.4F %.4F %.4F cm /%s Do Q',
+ ($newSize['width'] / $originalSize['width']),
+ ($newSize['height'] / $originalSize['height']),
+ $x * $this->k,
+ ($this->h - $y - $newSize['height']) * $this->k,
+ $template['id']
+ )
+ );
+
+ return $newSize;
+ }
+
+ /**
+ * Get the size of a template.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $tpl The template id
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @return array|bool An array with following keys: width, height, 0 (=width), 1 (=height), orientation (L or P)
+ */
+ public function getTemplateSize($tpl, $width = null, $height = null)
+ {
+ if (!isset($this->templates[$tpl])) {
+ return false;
+ }
+
+ if ($width === null && $height === null) {
+ $width = $this->templates[$tpl]['width'];
+ $height = $this->templates[$tpl]['height'];
+ } elseif ($width === null) {
+ $width = $height * $this->templates[$tpl]['width'] / $this->templates[$tpl]['height'];
+ }
+
+ if ($height === null) {
+ $height = $width * $this->templates[$tpl]['height'] / $this->templates[$tpl]['width'];
+ }
+
+ if ($height <= 0. || $width <= 0.) {
+ throw new \InvalidArgumentException('Width or height parameter needs to be larger than zero.');
+ }
+
+ return [
+ 'width' => $width,
+ 'height' => $height,
+ 0 => $width,
+ 1 => $height,
+ 'orientation' => $width > $height ? 'L' : 'P'
+ ];
+ }
+
+ /**
+ * Begins a new template.
+ *
+ * @param float|int|null $width The width of the template. If null, the current page width is used.
+ * @param float|int|null $height The height of the template. If null, the current page height is used.
+ * @param bool $groupXObject Define the form XObject as a group XObject to support transparency (if used).
+ * @return int A template identifier.
+ */
+ public function beginTemplate($width = null, $height = null, $groupXObject = false)
+ {
+ if ($width === null) {
+ $width = $this->w;
+ }
+
+ if ($height === null) {
+ $height = $this->h;
+ }
+
+ $templateId = $this->getNextTemplateId();
+
+ // initiate buffer with current state of FPDF
+ $buffer = "2 J\n"
+ . \sprintf('%.2F w', $this->LineWidth * $this->k) . "\n";
+
+ if ($this->FontFamily) {
+ $buffer .= \sprintf("BT /F%d %.2F Tf ET\n", $this->CurrentFont['i'], $this->FontSizePt);
+ }
+
+ if ($this->DrawColor !== '0 G') {
+ $buffer .= $this->DrawColor . "\n";
+ }
+ if ($this->FillColor !== '0 g') {
+ $buffer .= $this->FillColor . "\n";
+ }
+
+ if ($groupXObject && \version_compare('1.4', $this->PDFVersion, '>')) {
+ $this->PDFVersion = '1.4';
+ }
+
+ $this->templates[$templateId] = [
+ 'objectNumber' => null,
+ 'id' => 'TPL' . $templateId,
+ 'buffer' => $buffer,
+ 'width' => $width,
+ 'height' => $height,
+ 'groupXObject' => $groupXObject,
+ 'state' => [
+ 'x' => $this->x,
+ 'y' => $this->y,
+ 'AutoPageBreak' => $this->AutoPageBreak,
+ 'bMargin' => $this->bMargin,
+ 'tMargin' => $this->tMargin,
+ 'lMargin' => $this->lMargin,
+ 'rMargin' => $this->rMargin,
+ 'h' => $this->h,
+ 'w' => $this->w,
+ 'FontFamily' => $this->FontFamily,
+ 'FontStyle' => $this->FontStyle,
+ 'FontSizePt' => $this->FontSizePt,
+ 'FontSize' => $this->FontSize,
+ 'underline' => $this->underline,
+ 'TextColor' => $this->TextColor,
+ 'DrawColor' => $this->DrawColor,
+ 'FillColor' => $this->FillColor,
+ 'ColorFlag' => $this->ColorFlag
+ ]
+ ];
+
+ $this->SetAutoPageBreak(false);
+ $this->currentTemplateId = $templateId;
+
+ $this->h = $height;
+ $this->w = $width;
+
+ $this->SetXY($this->lMargin, $this->tMargin);
+ $this->SetRightMargin($this->w - $width + $this->rMargin);
+
+ return $templateId;
+ }
+
+ /**
+ * Ends a template.
+ *
+ * @return bool|int|null A template identifier.
+ */
+ public function endTemplate()
+ {
+ if ($this->currentTemplateId === null) {
+ return false;
+ }
+
+ $templateId = $this->currentTemplateId;
+ $template = $this->templates[$templateId];
+
+ $state = $template['state'];
+ $this->SetXY($state['x'], $state['y']);
+ $this->tMargin = $state['tMargin'];
+ $this->lMargin = $state['lMargin'];
+ $this->rMargin = $state['rMargin'];
+ $this->h = $state['h'];
+ $this->w = $state['w'];
+ $this->SetAutoPageBreak($state['AutoPageBreak'], $state['bMargin']);
+
+ $this->FontFamily = $state['FontFamily'];
+ $this->FontStyle = $state['FontStyle'];
+ $this->FontSizePt = $state['FontSizePt'];
+ $this->FontSize = $state['FontSize'];
+
+ $this->TextColor = $state['TextColor'];
+ $this->DrawColor = $state['DrawColor'];
+ $this->FillColor = $state['FillColor'];
+ $this->ColorFlag = $state['ColorFlag'];
+
+ $this->underline = $state['underline'];
+
+ $fontKey = $this->FontFamily . $this->FontStyle;
+ if ($fontKey) {
+ $this->CurrentFont =& $this->fonts[$fontKey];
+ } else {
+ unset($this->CurrentFont);
+ }
+
+ $this->currentTemplateId = null;
+
+ return $templateId;
+ }
+
+ /**
+ * Get the next template id.
+ *
+ * @return int
+ */
+ protected function getNextTemplateId()
+ {
+ return $this->templateId++;
+ }
+
+ /* overwritten FPDF methods: */
+
+ /**
+ * @inheritdoc
+ */
+ public function AddPage($orientation = '', $size = '', $rotation = 0)
+ {
+ if ($this->currentTemplateId !== null) {
+ throw new \BadMethodCallException('Pages cannot be added when writing to a template.');
+ }
+ parent::AddPage($orientation, $size, $rotation);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function Link($x, $y, $w, $h, $link)
+ {
+ if ($this->currentTemplateId !== null) {
+ throw new \BadMethodCallException('Links cannot be set when writing to a template.');
+ }
+ parent::Link($x, $y, $w, $h, $link);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function SetLink($link, $y = 0, $page = -1)
+ {
+ if ($this->currentTemplateId !== null) {
+ throw new \BadMethodCallException('Links cannot be set when writing to a template.');
+ }
+ return parent::SetLink($link, $y, $page);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function SetDrawColor($r, $g = null, $b = null)
+ {
+ parent::SetDrawColor($r, $g, $b);
+ if ($this->page === 0 && $this->currentTemplateId !== null) {
+ $this->_out($this->DrawColor);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function SetFillColor($r, $g = null, $b = null)
+ {
+ parent::SetFillColor($r, $g, $b);
+ if ($this->page === 0 && $this->currentTemplateId !== null) {
+ $this->_out($this->FillColor);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function SetLineWidth($width)
+ {
+ parent::SetLineWidth($width);
+ if ($this->page === 0 && $this->currentTemplateId !== null) {
+ $this->_out(\sprintf('%.2F w', $width * $this->k));
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function SetFont($family, $style = '', $size = 0)
+ {
+ parent::SetFont($family, $style, $size);
+ if ($this->page === 0 && $this->currentTemplateId !== null) {
+ $this->_out(\sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function SetFontSize($size)
+ {
+ parent::SetFontSize($size);
+ if ($this->page === 0 && $this->currentTemplateId !== null) {
+ $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function _putimages()
+ {
+ parent::_putimages();
+
+ foreach ($this->templates as $key => $template) {
+ $this->_newobj();
+ $this->templates[$key]['objectNumber'] = $this->n;
+
+ $this->_put('<</Type /XObject /Subtype /Form /FormType 1');
+ $this->_put(\sprintf(
+ '/BBox[0 0 %.2F %.2F]',
+ $template['width'] * $this->k,
+ $template['height'] * $this->k
+ ));
+ $this->_put('/Resources 2 0 R'); // default resources dictionary of FPDF
+
+ if ($this->compress) {
+ $buffer = \gzcompress($template['buffer']);
+ $this->_put('/Filter/FlateDecode');
+ } else {
+ $buffer = $template['buffer'];
+ }
+
+ $this->_put('/Length ' . \strlen($buffer));
+
+ if ($template['groupXObject']) {
+ $this->_put('/Group <</Type/Group/S/Transparency>>');
+ }
+
+ $this->_put('>>');
+ $this->_putstream($buffer);
+ $this->_put('endobj');
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function _putxobjectdict()
+ {
+ foreach ($this->templates as $key => $template) {
+ $this->_put('/' . $template['id'] . ' ' . $template['objectNumber'] . ' 0 R');
+ }
+
+ parent::_putxobjectdict();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function _out($s)
+ {
+ if ($this->currentTemplateId !== null) {
+ $this->templates[$this->currentTemplateId]['buffer'] .= $s . "\n";
+ } else {
+ parent::_out($s);
+ }
+ }
+}
diff --git a/vendor/setasign/fpdi/src/Fpdi.php b/vendor/setasign/fpdi/src/Fpdi.php
new file mode 100644
index 0000000..157f87c
--- /dev/null
+++ b/vendor/setasign/fpdi/src/Fpdi.php
@@ -0,0 +1,153 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi;
+
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+use setasign\Fpdi\PdfParser\PdfParserException;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
+use setasign\Fpdi\PdfParser\Type\PdfNull;
+
+/**
+ * Class Fpdi
+ *
+ * This class let you import pages of existing PDF documents into a reusable structure for FPDF.
+ */
+class Fpdi extends FpdfTpl
+{
+ use FpdiTrait;
+
+ /**
+ * FPDI version
+ *
+ * @string
+ */
+ const VERSION = '2.3.6';
+
+ protected function _enddoc()
+ {
+ parent::_enddoc();
+ $this->cleanUp();
+ }
+
+ /**
+ * Draws an imported page or a template onto the page or another template.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $tpl The template id
+ * @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array
+ * with the keys "x", "y", "width", "height", "adjustPageSize".
+ * @param float|int $y The ordinate of upper-left corner.
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @param bool $adjustPageSize
+ * @return array The size
+ * @see Fpdi::getTemplateSize()
+ */
+ public function useTemplate($tpl, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false)
+ {
+ if (isset($this->importedPages[$tpl])) {
+ $size = $this->useImportedPage($tpl, $x, $y, $width, $height, $adjustPageSize);
+ if ($this->currentTemplateId !== null) {
+ $this->templates[$this->currentTemplateId]['resources']['templates']['importedPages'][$tpl] = $tpl;
+ }
+ return $size;
+ }
+
+ return parent::useTemplate($tpl, $x, $y, $width, $height, $adjustPageSize);
+ }
+
+ /**
+ * Get the size of an imported page or template.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $tpl The template id
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @return array|bool An array with following keys: width, height, 0 (=width), 1 (=height), orientation (L or P)
+ */
+ public function getTemplateSize($tpl, $width = null, $height = null)
+ {
+ $size = parent::getTemplateSize($tpl, $width, $height);
+ if ($size === false) {
+ return $this->getImportedPageSize($tpl, $width, $height);
+ }
+
+ return $size;
+ }
+
+ /**
+ * @inheritdoc
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ protected function _putimages()
+ {
+ $this->currentReaderId = null;
+ parent::_putimages();
+
+ foreach ($this->importedPages as $key => $pageData) {
+ $this->_newobj();
+ $this->importedPages[$key]['objectNumber'] = $this->n;
+ $this->currentReaderId = $pageData['readerId'];
+ $this->writePdfType($pageData['stream']);
+ $this->_put('endobj');
+ }
+
+ foreach (\array_keys($this->readers) as $readerId) {
+ $parser = $this->getPdfReader($readerId)->getParser();
+ $this->currentReaderId = $readerId;
+
+ while (($objectNumber = \array_pop($this->objectsToCopy[$readerId])) !== null) {
+ try {
+ $object = $parser->getIndirectObject($objectNumber);
+ } catch (CrossReferenceException $e) {
+ if ($e->getCode() === CrossReferenceException::OBJECT_NOT_FOUND) {
+ $object = PdfIndirectObject::create($objectNumber, 0, new PdfNull());
+ } else {
+ throw $e;
+ }
+ }
+
+ $this->writePdfType($object);
+ }
+ }
+
+ $this->currentReaderId = null;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function _putxobjectdict()
+ {
+ foreach ($this->importedPages as $key => $pageData) {
+ $this->_put('/' . $pageData['id'] . ' ' . $pageData['objectNumber'] . ' 0 R');
+ }
+
+ parent::_putxobjectdict();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function _put($s, $newLine = true)
+ {
+ if ($newLine) {
+ $this->buffer .= $s . "\n";
+ } else {
+ $this->buffer .= $s;
+ }
+ }
+}
diff --git a/vendor/setasign/fpdi/src/FpdiException.php b/vendor/setasign/fpdi/src/FpdiException.php
new file mode 100644
index 0000000..2286667
--- /dev/null
+++ b/vendor/setasign/fpdi/src/FpdiException.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi;
+
+/**
+ * Base exception class for the FPDI package.
+ */
+class FpdiException extends \Exception
+{
+}
diff --git a/vendor/setasign/fpdi/src/FpdiTrait.php b/vendor/setasign/fpdi/src/FpdiTrait.php
new file mode 100644
index 0000000..3b29857
--- /dev/null
+++ b/vendor/setasign/fpdi/src/FpdiTrait.php
@@ -0,0 +1,559 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi;
+
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+use setasign\Fpdi\PdfParser\Filter\FilterException;
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\PdfParserException;
+use setasign\Fpdi\PdfParser\StreamReader;
+use setasign\Fpdi\PdfParser\Type\PdfArray;
+use setasign\Fpdi\PdfParser\Type\PdfBoolean;
+use setasign\Fpdi\PdfParser\Type\PdfDictionary;
+use setasign\Fpdi\PdfParser\Type\PdfHexString;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObjectReference;
+use setasign\Fpdi\PdfParser\Type\PdfName;
+use setasign\Fpdi\PdfParser\Type\PdfNull;
+use setasign\Fpdi\PdfParser\Type\PdfNumeric;
+use setasign\Fpdi\PdfParser\Type\PdfStream;
+use setasign\Fpdi\PdfParser\Type\PdfString;
+use setasign\Fpdi\PdfParser\Type\PdfToken;
+use setasign\Fpdi\PdfParser\Type\PdfType;
+use setasign\Fpdi\PdfParser\Type\PdfTypeException;
+use setasign\Fpdi\PdfReader\PageBoundaries;
+use setasign\Fpdi\PdfReader\PdfReader;
+use setasign\Fpdi\PdfReader\PdfReaderException;
+use /* This namespace/class is used by the commercial FPDI PDF-Parser add-on. */
+ /** @noinspection PhpUndefinedClassInspection */
+ /** @noinspection PhpUndefinedNamespaceInspection */
+ setasign\FpdiPdfParser\PdfParser\PdfParser as FpdiPdfParser;
+
+/**
+ * The FpdiTrait
+ *
+ * This trait offers the core functionalities of FPDI. By passing them to a trait we can reuse it with e.g. TCPDF in a
+ * very easy way.
+ */
+trait FpdiTrait
+{
+ /**
+ * The pdf reader instances.
+ *
+ * @var PdfReader[]
+ */
+ protected $readers = [];
+
+ /**
+ * Instances created internally.
+ *
+ * @var array
+ */
+ protected $createdReaders = [];
+
+ /**
+ * The current reader id.
+ *
+ * @var string|null
+ */
+ protected $currentReaderId;
+
+ /**
+ * Data of all imported pages.
+ *
+ * @var array
+ */
+ protected $importedPages = [];
+
+ /**
+ * A map from object numbers of imported objects to new assigned object numbers by FPDF.
+ *
+ * @var array
+ */
+ protected $objectMap = [];
+
+ /**
+ * An array with information about objects, which needs to be copied to the resulting document.
+ *
+ * @var array
+ */
+ protected $objectsToCopy = [];
+
+ /**
+ * Release resources and file handles.
+ *
+ * This method is called internally when the document is created successfully. By default it only cleans up
+ * stream reader instances which were created internally.
+ *
+ * @param bool $allReaders
+ */
+ public function cleanUp($allReaders = false)
+ {
+ $readers = $allReaders ? array_keys($this->readers) : $this->createdReaders;
+ foreach ($readers as $id) {
+ $this->readers[$id]->getParser()->getStreamReader()->cleanUp();
+ unset($this->readers[$id]);
+ }
+
+ $this->createdReaders = [];
+ }
+
+ /**
+ * Set the minimal PDF version.
+ *
+ * @param string $pdfVersion
+ */
+ protected function setMinPdfVersion($pdfVersion)
+ {
+ if (\version_compare($pdfVersion, $this->PDFVersion, '>')) {
+ $this->PDFVersion = $pdfVersion;
+ }
+ }
+
+ /** @noinspection PhpUndefinedClassInspection */
+ /**
+ * Get a new pdf parser instance.
+ *
+ * @param StreamReader $streamReader
+ * @return PdfParser|FpdiPdfParser
+ */
+ protected function getPdfParserInstance(StreamReader $streamReader)
+ {
+ // note: if you get an exception here - turn off errors/warnings on not found for your autoloader.
+ // psr-4 (https://www.php-fig.org/psr/psr-4/) says: Autoloader implementations MUST NOT throw
+ // exceptions, MUST NOT raise errors of any level, and SHOULD NOT return a value.
+ /** @noinspection PhpUndefinedClassInspection */
+ if (\class_exists(FpdiPdfParser::class)) {
+ /** @noinspection PhpUndefinedClassInspection */
+ return new FpdiPdfParser($streamReader);
+ }
+
+ return new PdfParser($streamReader);
+ }
+
+ /**
+ * Get an unique reader id by the $file parameter.
+ *
+ * @param string|resource|PdfReader|StreamReader $file An open file descriptor, a path to a file, a PdfReader
+ * instance or a StreamReader instance.
+ * @return string
+ */
+ protected function getPdfReaderId($file)
+ {
+ if (\is_resource($file)) {
+ $id = (string) $file;
+ } elseif (\is_string($file)) {
+ $id = \realpath($file);
+ if ($id === false) {
+ $id = $file;
+ }
+ } elseif (\is_object($file)) {
+ $id = \spl_object_hash($file);
+ } else {
+ throw new \InvalidArgumentException(
+ \sprintf('Invalid type in $file parameter (%s)', \gettype($file))
+ );
+ }
+
+ /** @noinspection OffsetOperationsInspection */
+ if (isset($this->readers[$id])) {
+ return $id;
+ }
+
+ if (\is_resource($file)) {
+ $streamReader = new StreamReader($file);
+ } elseif (\is_string($file)) {
+ $streamReader = StreamReader::createByFile($file);
+ $this->createdReaders[] = $id;
+ } else {
+ $streamReader = $file;
+ }
+
+ $reader = new PdfReader($this->getPdfParserInstance($streamReader));
+ /** @noinspection OffsetOperationsInspection */
+ $this->readers[$id] = $reader;
+
+ return $id;
+ }
+
+ /**
+ * Get a pdf reader instance by its id.
+ *
+ * @param string $id
+ * @return PdfReader
+ */
+ protected function getPdfReader($id)
+ {
+ if (isset($this->readers[$id])) {
+ return $this->readers[$id];
+ }
+
+ throw new \InvalidArgumentException(
+ \sprintf('No pdf reader with the given id (%s) exists.', $id)
+ );
+ }
+
+ /**
+ * Set the source PDF file.
+ *
+ * @param string|resource|StreamReader $file Path to the file or a stream resource or a StreamReader instance.
+ * @return int The page count of the PDF document.
+ * @throws PdfParserException
+ */
+ public function setSourceFile($file)
+ {
+ $this->currentReaderId = $this->getPdfReaderId($file);
+ $this->objectsToCopy[$this->currentReaderId] = [];
+
+ $reader = $this->getPdfReader($this->currentReaderId);
+ $this->setMinPdfVersion($reader->getPdfVersion());
+
+ return $reader->getPageCount();
+ }
+
+ /**
+ * Imports a page.
+ *
+ * @param int $pageNumber The page number.
+ * @param string $box The page boundary to import. Default set to PageBoundaries::CROP_BOX.
+ * @param bool $groupXObject Define the form XObject as a group XObject to support transparency (if used).
+ * @return string A unique string identifying the imported page.
+ * @throws CrossReferenceException
+ * @throws FilterException
+ * @throws PdfParserException
+ * @throws PdfTypeException
+ * @throws PdfReaderException
+ * @see PageBoundaries
+ */
+ public function importPage($pageNumber, $box = PageBoundaries::CROP_BOX, $groupXObject = true)
+ {
+ if (null === $this->currentReaderId) {
+ throw new \BadMethodCallException('No reader initiated. Call setSourceFile() first.');
+ }
+
+ $pageId = $this->currentReaderId;
+
+ $pageNumber = (int)$pageNumber;
+ $pageId .= '|' . $pageNumber . '|' . ($groupXObject ? '1' : '0');
+
+ // for backwards compatibility with FPDI 1
+ $box = \ltrim($box, '/');
+ if (!PageBoundaries::isValidName($box)) {
+ throw new \InvalidArgumentException(
+ \sprintf('Box name is invalid: "%s"', $box)
+ );
+ }
+
+ $pageId .= '|' . $box;
+
+ if (isset($this->importedPages[$pageId])) {
+ return $pageId;
+ }
+
+ $reader = $this->getPdfReader($this->currentReaderId);
+ $page = $reader->getPage($pageNumber);
+
+ $bbox = $page->getBoundary($box);
+ if ($bbox === false) {
+ throw new PdfReaderException(
+ \sprintf("Page doesn't have a boundary box (%s).", $box),
+ PdfReaderException::MISSING_DATA
+ );
+ }
+
+ $dict = new PdfDictionary();
+ $dict->value['Type'] = PdfName::create('XObject');
+ $dict->value['Subtype'] = PdfName::create('Form');
+ $dict->value['FormType'] = PdfNumeric::create(1);
+ $dict->value['BBox'] = $bbox->toPdfArray();
+
+ if ($groupXObject) {
+ $this->setMinPdfVersion('1.4');
+ $dict->value['Group'] = PdfDictionary::create([
+ 'Type' => PdfName::create('Group'),
+ 'S' => PdfName::create('Transparency')
+ ]);
+ }
+
+ $resources = $page->getAttribute('Resources');
+ if ($resources !== null) {
+ $dict->value['Resources'] = $resources;
+ }
+
+ list($width, $height) = $page->getWidthAndHeight($box);
+
+ $a = 1;
+ $b = 0;
+ $c = 0;
+ $d = 1;
+ $e = -$bbox->getLlx();
+ $f = -$bbox->getLly();
+
+ $rotation = $page->getRotation();
+
+ if ($rotation !== 0) {
+ $rotation *= -1;
+ $angle = $rotation * M_PI / 180;
+ $a = \cos($angle);
+ $b = \sin($angle);
+ $c = -$b;
+ $d = $a;
+
+ switch ($rotation) {
+ case -90:
+ $e = -$bbox->getLly();
+ $f = $bbox->getUrx();
+ break;
+ case -180:
+ $e = $bbox->getUrx();
+ $f = $bbox->getUry();
+ break;
+ case -270:
+ $e = $bbox->getUry();
+ $f = -$bbox->getLlx();
+ break;
+ }
+ }
+
+ // we need to rotate/translate
+ if ($a != 1 || $b != 0 || $c != 0 || $d != 1 || $e != 0 || $f != 0) {
+ $dict->value['Matrix'] = PdfArray::create([
+ PdfNumeric::create($a), PdfNumeric::create($b), PdfNumeric::create($c),
+ PdfNumeric::create($d), PdfNumeric::create($e), PdfNumeric::create($f)
+ ]);
+ }
+
+ // try to use the existing content stream
+ $pageDict = $page->getPageDictionary();
+
+ try {
+ $contentsObject = PdfType::resolve(PdfDictionary::get($pageDict, 'Contents'), $reader->getParser(), true);
+ $contents = PdfType::resolve($contentsObject, $reader->getParser());
+
+ // just copy the stream reference if it is only a single stream
+ if (
+ ($contentsIsStream = ($contents instanceof PdfStream))
+ || ($contents instanceof PdfArray && \count($contents->value) === 1)
+ ) {
+ if ($contentsIsStream) {
+ /**
+ * @var PdfIndirectObject $contentsObject
+ */
+ $stream = $contents;
+ } else {
+ $stream = PdfType::resolve($contents->value[0], $reader->getParser());
+ }
+
+ $filter = PdfDictionary::get($stream->value, 'Filter');
+ if (!$filter instanceof PdfNull) {
+ $dict->value['Filter'] = $filter;
+ }
+ $length = PdfType::resolve(PdfDictionary::get($stream->value, 'Length'), $reader->getParser());
+ $dict->value['Length'] = $length;
+ $stream->value = $dict;
+ // otherwise extract it from the array and re-compress the whole stream
+ } else {
+ $streamContent = $this->compress
+ ? \gzcompress($page->getContentStream())
+ : $page->getContentStream();
+
+ $dict->value['Length'] = PdfNumeric::create(\strlen($streamContent));
+ if ($this->compress) {
+ $dict->value['Filter'] = PdfName::create('FlateDecode');
+ }
+
+ $stream = PdfStream::create($dict, $streamContent);
+ }
+ // Catch faulty pages and use an empty content stream
+ } catch (FpdiException $e) {
+ $dict->value['Length'] = PdfNumeric::create(0);
+ $stream = PdfStream::create($dict, '');
+ }
+
+ $this->importedPages[$pageId] = [
+ 'objectNumber' => null,
+ 'readerId' => $this->currentReaderId,
+ 'id' => 'TPL' . $this->getNextTemplateId(),
+ 'width' => $width / $this->k,
+ 'height' => $height / $this->k,
+ 'stream' => $stream
+ ];
+
+ return $pageId;
+ }
+
+ /**
+ * Draws an imported page onto the page.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $pageId The page id
+ * @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array
+ * with the keys "x", "y", "width", "height", "adjustPageSize".
+ * @param float|int $y The ordinate of upper-left corner.
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @param bool $adjustPageSize
+ * @return array The size.
+ * @see Fpdi::getTemplateSize()
+ */
+ public function useImportedPage($pageId, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false)
+ {
+ if (\is_array($x)) {
+ /** @noinspection OffsetOperationsInspection */
+ unset($x['pageId']);
+ \extract($x, EXTR_IF_EXISTS);
+ /** @noinspection NotOptimalIfConditionsInspection */
+ if (\is_array($x)) {
+ $x = 0;
+ }
+ }
+
+ if (!isset($this->importedPages[$pageId])) {
+ throw new \InvalidArgumentException('Imported page does not exist!');
+ }
+
+ $importedPage = $this->importedPages[$pageId];
+
+ $originalSize = $this->getTemplateSize($pageId);
+ $newSize = $this->getTemplateSize($pageId, $width, $height);
+ if ($adjustPageSize) {
+ $this->setPageFormat($newSize, $newSize['orientation']);
+ }
+
+ $this->_out(
+ // reset standard values, translate and scale
+ \sprintf(
+ 'q 0 J 1 w 0 j 0 G 0 g %.4F 0 0 %.4F %.4F %.4F cm /%s Do Q',
+ ($newSize['width'] / $originalSize['width']),
+ ($newSize['height'] / $originalSize['height']),
+ $x * $this->k,
+ ($this->h - $y - $newSize['height']) * $this->k,
+ $importedPage['id']
+ )
+ );
+
+ return $newSize;
+ }
+
+ /**
+ * Get the size of an imported page.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $tpl The template id
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @return array|bool An array with following keys: width, height, 0 (=width), 1 (=height), orientation (L or P)
+ */
+ public function getImportedPageSize($tpl, $width = null, $height = null)
+ {
+ if (isset($this->importedPages[$tpl])) {
+ $importedPage = $this->importedPages[$tpl];
+
+ if ($width === null && $height === null) {
+ $width = $importedPage['width'];
+ $height = $importedPage['height'];
+ } elseif ($width === null) {
+ $width = $height * $importedPage['width'] / $importedPage['height'];
+ }
+
+ if ($height === null) {
+ $height = $width * $importedPage['height'] / $importedPage['width'];
+ }
+
+ if ($height <= 0. || $width <= 0.) {
+ throw new \InvalidArgumentException('Width or height parameter needs to be larger than zero.');
+ }
+
+ return [
+ 'width' => $width,
+ 'height' => $height,
+ 0 => $width,
+ 1 => $height,
+ 'orientation' => $width > $height ? 'L' : 'P'
+ ];
+ }
+
+ return false;
+ }
+
+ /**
+ * Writes a PdfType object to the resulting buffer.
+ *
+ * @param PdfType $value
+ * @throws PdfTypeException
+ */
+ protected function writePdfType(PdfType $value)
+ {
+ if ($value instanceof PdfNumeric) {
+ if (\is_int($value->value)) {
+ $this->_put($value->value . ' ', false);
+ } else {
+ $this->_put(\rtrim(\rtrim(\sprintf('%.5F', $value->value), '0'), '.') . ' ', false);
+ }
+ } elseif ($value instanceof PdfName) {
+ $this->_put('/' . $value->value . ' ', false);
+ } elseif ($value instanceof PdfString) {
+ $this->_put('(' . $value->value . ')', false);
+ } elseif ($value instanceof PdfHexString) {
+ $this->_put('<' . $value->value . '>');
+ } elseif ($value instanceof PdfBoolean) {
+ $this->_put($value->value ? 'true ' : 'false ', false);
+ } elseif ($value instanceof PdfArray) {
+ $this->_put('[', false);
+ foreach ($value->value as $entry) {
+ $this->writePdfType($entry);
+ }
+ $this->_put(']');
+ } elseif ($value instanceof PdfDictionary) {
+ $this->_put('<<', false);
+ foreach ($value->value as $name => $entry) {
+ $this->_put('/' . $name . ' ', false);
+ $this->writePdfType($entry);
+ }
+ $this->_put('>>');
+ } elseif ($value instanceof PdfToken) {
+ $this->_put($value->value);
+ } elseif ($value instanceof PdfNull) {
+ $this->_put('null ');
+ } elseif ($value instanceof PdfStream) {
+ /**
+ * @var $value PdfStream
+ */
+ $this->writePdfType($value->value);
+ $this->_put('stream');
+ $this->_put($value->getStream());
+ $this->_put('endstream');
+ } elseif ($value instanceof PdfIndirectObjectReference) {
+ if (!isset($this->objectMap[$this->currentReaderId])) {
+ $this->objectMap[$this->currentReaderId] = [];
+ }
+
+ if (!isset($this->objectMap[$this->currentReaderId][$value->value])) {
+ $this->objectMap[$this->currentReaderId][$value->value] = ++$this->n;
+ $this->objectsToCopy[$this->currentReaderId][] = $value->value;
+ }
+
+ $this->_put($this->objectMap[$this->currentReaderId][$value->value] . ' 0 R ', false);
+ } elseif ($value instanceof PdfIndirectObject) {
+ /**
+ * @var PdfIndirectObject $value
+ */
+ $n = $this->objectMap[$this->currentReaderId][$value->objectNumber];
+ $this->_newobj($n);
+ $this->writePdfType($value->value);
+ $this->_put('endobj');
+ }
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/CrossReference/AbstractReader.php b/vendor/setasign/fpdi/src/PdfParser/CrossReference/AbstractReader.php
new file mode 100644
index 0000000..b54237b
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/CrossReference/AbstractReader.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\CrossReference;
+
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\Type\PdfDictionary;
+use setasign\Fpdi\PdfParser\Type\PdfToken;
+use setasign\Fpdi\PdfParser\Type\PdfTypeException;
+
+/**
+ * Abstract class for cross-reference reader classes.
+ */
+abstract class AbstractReader
+{
+ /**
+ * @var PdfParser
+ */
+ protected $parser;
+
+ /**
+ * @var PdfDictionary
+ */
+ protected $trailer;
+
+ /**
+ * AbstractReader constructor.
+ *
+ * @param PdfParser $parser
+ * @throws CrossReferenceException
+ * @throws PdfTypeException
+ */
+ public function __construct(PdfParser $parser)
+ {
+ $this->parser = $parser;
+ $this->readTrailer();
+ }
+
+ /**
+ * Get the trailer dictionary.
+ *
+ * @return PdfDictionary
+ */
+ public function getTrailer()
+ {
+ return $this->trailer;
+ }
+
+ /**
+ * Read the trailer dictionary.
+ *
+ * @throws CrossReferenceException
+ * @throws PdfTypeException
+ */
+ protected function readTrailer()
+ {
+ try {
+ $trailerKeyword = $this->parser->readValue(null, PdfToken::class);
+ if ($trailerKeyword->value !== 'trailer') {
+ throw new CrossReferenceException(
+ \sprintf(
+ 'Unexpected end of cross reference. "trailer"-keyword expected, got: %s.',
+ $trailerKeyword->value
+ ),
+ CrossReferenceException::UNEXPECTED_END
+ );
+ }
+ } catch (PdfTypeException $e) {
+ throw new CrossReferenceException(
+ 'Unexpected end of cross reference. "trailer"-keyword expected, got an invalid object type.',
+ CrossReferenceException::UNEXPECTED_END,
+ $e
+ );
+ }
+
+ try {
+ $trailer = $this->parser->readValue(null, PdfDictionary::class);
+ } catch (PdfTypeException $e) {
+ throw new CrossReferenceException(
+ 'Unexpected end of cross reference. Trailer not found.',
+ CrossReferenceException::UNEXPECTED_END,
+ $e
+ );
+ }
+
+ $this->trailer = $trailer;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/CrossReference/CrossReference.php b/vendor/setasign/fpdi/src/PdfParser/CrossReference/CrossReference.php
new file mode 100644
index 0000000..c47e8c4
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/CrossReference/CrossReference.php
@@ -0,0 +1,326 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\CrossReference;
+
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\Type\PdfDictionary;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
+use setasign\Fpdi\PdfParser\Type\PdfNumeric;
+use setasign\Fpdi\PdfParser\Type\PdfStream;
+use setasign\Fpdi\PdfParser\Type\PdfToken;
+use setasign\Fpdi\PdfParser\Type\PdfTypeException;
+
+/**
+ * Class CrossReference
+ *
+ * This class processes the standard cross reference of a PDF document.
+ */
+class CrossReference
+{
+ /**
+ * The byte length in which the "startxref" keyword should be searched.
+ *
+ * @var int
+ */
+ public static $trailerSearchLength = 5500;
+
+ /**
+ * @var int
+ */
+ protected $fileHeaderOffset = 0;
+
+ /**
+ * @var PdfParser
+ */
+ protected $parser;
+
+ /**
+ * @var ReaderInterface[]
+ */
+ protected $readers = [];
+
+ /**
+ * CrossReference constructor.
+ *
+ * @param PdfParser $parser
+ * @throws CrossReferenceException
+ * @throws PdfTypeException
+ */
+ public function __construct(PdfParser $parser, $fileHeaderOffset = 0)
+ {
+ $this->parser = $parser;
+ $this->fileHeaderOffset = $fileHeaderOffset;
+
+ $offset = $this->findStartXref();
+ $reader = null;
+ /** @noinspection TypeUnsafeComparisonInspection */
+ while ($offset != false) { // By doing an unsafe comparsion we ignore faulty references to byte offset 0
+ try {
+ $reader = $this->readXref($offset + $this->fileHeaderOffset);
+ } catch (CrossReferenceException $e) {
+ // sometimes the file header offset is part of the byte offsets, so let's retry by resetting it to zero.
+ if ($e->getCode() === CrossReferenceException::INVALID_DATA && $this->fileHeaderOffset !== 0) {
+ $this->fileHeaderOffset = 0;
+ $reader = $this->readXref($offset + $this->fileHeaderOffset);
+ } else {
+ throw $e;
+ }
+ }
+
+ $trailer = $reader->getTrailer();
+ $this->checkForEncryption($trailer);
+ $this->readers[] = $reader;
+
+ if (isset($trailer->value['Prev'])) {
+ $offset = $trailer->value['Prev']->value;
+ } else {
+ $offset = false;
+ }
+ }
+
+ // fix faulty sub-section header
+ if ($reader instanceof FixedReader) {
+ /**
+ * @var FixedReader $reader
+ */
+ $reader->fixFaultySubSectionShift();
+ }
+
+ if ($reader === null) {
+ throw new CrossReferenceException('No cross-reference found.', CrossReferenceException::NO_XREF_FOUND);
+ }
+ }
+
+ /**
+ * Get the size of the cross reference.
+ *
+ * @return integer
+ */
+ public function getSize()
+ {
+ return $this->getTrailer()->value['Size']->value;
+ }
+
+ /**
+ * Get the trailer dictionary.
+ *
+ * @return PdfDictionary
+ */
+ public function getTrailer()
+ {
+ return $this->readers[0]->getTrailer();
+ }
+
+ /**
+ * Get the cross reference readser instances.
+ *
+ * @return ReaderInterface[]
+ */
+ public function getReaders()
+ {
+ return $this->readers;
+ }
+
+ /**
+ * Get the offset by an object number.
+ *
+ * @param int $objectNumber
+ * @return integer|bool
+ */
+ public function getOffsetFor($objectNumber)
+ {
+ foreach ($this->getReaders() as $reader) {
+ $offset = $reader->getOffsetFor($objectNumber);
+ if ($offset !== false) {
+ return $offset;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get an indirect object by its object number.
+ *
+ * @param int $objectNumber
+ * @return PdfIndirectObject
+ * @throws CrossReferenceException
+ */
+ public function getIndirectObject($objectNumber)
+ {
+ $offset = $this->getOffsetFor($objectNumber);
+ if ($offset === false) {
+ throw new CrossReferenceException(
+ \sprintf('Object (id:%s) not found.', $objectNumber),
+ CrossReferenceException::OBJECT_NOT_FOUND
+ );
+ }
+
+ $parser = $this->parser;
+
+ $parser->getTokenizer()->clearStack();
+ $parser->getStreamReader()->reset($offset + $this->fileHeaderOffset);
+
+ try {
+ /** @var PdfIndirectObject $object */
+ $object = $parser->readValue(null, PdfIndirectObject::class);
+ } catch (PdfTypeException $e) {
+ throw new CrossReferenceException(
+ \sprintf('Object (id:%s) not found at location (%s).', $objectNumber, $offset),
+ CrossReferenceException::OBJECT_NOT_FOUND,
+ $e
+ );
+ }
+
+ if ($object->objectNumber !== $objectNumber) {
+ throw new CrossReferenceException(
+ \sprintf('Wrong object found, got %s while %s was expected.', $object->objectNumber, $objectNumber),
+ CrossReferenceException::OBJECT_NOT_FOUND
+ );
+ }
+
+ return $object;
+ }
+
+ /**
+ * Read the cross-reference table at a given offset.
+ *
+ * Internally the method will try to evaluate the best reader for this cross-reference.
+ *
+ * @param int $offset
+ * @return ReaderInterface
+ * @throws CrossReferenceException
+ * @throws PdfTypeException
+ */
+ protected function readXref($offset)
+ {
+ $this->parser->getStreamReader()->reset($offset);
+ $this->parser->getTokenizer()->clearStack();
+ $initValue = $this->parser->readValue();
+
+ return $this->initReaderInstance($initValue);
+ }
+
+ /**
+ * Get a cross-reference reader instance.
+ *
+ * @param PdfToken|PdfIndirectObject $initValue
+ * @return ReaderInterface|bool
+ * @throws CrossReferenceException
+ * @throws PdfTypeException
+ */
+ protected function initReaderInstance($initValue)
+ {
+ $position = $this->parser->getStreamReader()->getPosition()
+ + $this->parser->getStreamReader()->getOffset() + $this->fileHeaderOffset;
+
+ if ($initValue instanceof PdfToken && $initValue->value === 'xref') {
+ try {
+ return new FixedReader($this->parser);
+ } catch (CrossReferenceException $e) {
+ $this->parser->getStreamReader()->reset($position);
+ $this->parser->getTokenizer()->clearStack();
+
+ return new LineReader($this->parser);
+ }
+ }
+
+ if ($initValue instanceof PdfIndirectObject) {
+ try {
+ $stream = PdfStream::ensure($initValue->value);
+ } catch (PdfTypeException $e) {
+ throw new CrossReferenceException(
+ 'Invalid object type at xref reference offset.',
+ CrossReferenceException::INVALID_DATA,
+ $e
+ );
+ }
+
+ $type = PdfDictionary::get($stream->value, 'Type');
+ if ($type->value !== 'XRef') {
+ throw new CrossReferenceException(
+ 'The xref position points to an incorrect object type.',
+ CrossReferenceException::INVALID_DATA
+ );
+ }
+
+ $this->checkForEncryption($stream->value);
+
+ throw new CrossReferenceException(
+ 'This PDF document probably uses a compression technique which is not supported by the ' .
+ 'free parser shipped with FPDI. (See https://www.setasign.com/fpdi-pdf-parser for more details)',
+ CrossReferenceException::COMPRESSED_XREF
+ );
+ }
+
+ throw new CrossReferenceException(
+ 'The xref position points to an incorrect object type.',
+ CrossReferenceException::INVALID_DATA
+ );
+ }
+
+ /**
+ * Check for encryption.
+ *
+ * @param PdfDictionary $dictionary
+ * @throws CrossReferenceException
+ */
+ protected function checkForEncryption(PdfDictionary $dictionary)
+ {
+ if (isset($dictionary->value['Encrypt'])) {
+ throw new CrossReferenceException(
+ 'This PDF document is encrypted and cannot be processed with FPDI.',
+ CrossReferenceException::ENCRYPTED
+ );
+ }
+ }
+
+ /**
+ * Find the start position for the first cross-reference.
+ *
+ * @return int The byte-offset position of the first cross-reference.
+ * @throws CrossReferenceException
+ */
+ protected function findStartXref()
+ {
+ $reader = $this->parser->getStreamReader();
+ $reader->reset(-self::$trailerSearchLength, self::$trailerSearchLength);
+
+ $buffer = $reader->getBuffer(false);
+ $pos = \strrpos($buffer, 'startxref');
+ $addOffset = 9;
+ if ($pos === false) {
+ // Some corrupted documents uses startref, instead of startxref
+ $pos = \strrpos($buffer, 'startref');
+ if ($pos === false) {
+ throw new CrossReferenceException(
+ 'Unable to find pointer to xref table',
+ CrossReferenceException::NO_STARTXREF_FOUND
+ );
+ }
+ $addOffset = 8;
+ }
+
+ $reader->setOffset($pos + $addOffset);
+
+ try {
+ $value = $this->parser->readValue(null, PdfNumeric::class);
+ } catch (PdfTypeException $e) {
+ throw new CrossReferenceException(
+ 'Invalid data after startxref keyword.',
+ CrossReferenceException::INVALID_DATA,
+ $e
+ );
+ }
+
+ return $value->value;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/CrossReference/CrossReferenceException.php b/vendor/setasign/fpdi/src/PdfParser/CrossReference/CrossReferenceException.php
new file mode 100644
index 0000000..7d88d5d
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/CrossReference/CrossReferenceException.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\CrossReference;
+
+use setasign\Fpdi\PdfParser\PdfParserException;
+
+/**
+ * Exception used by the CrossReference and Reader classes.
+ */
+class CrossReferenceException extends PdfParserException
+{
+ /**
+ * @var int
+ */
+ const INVALID_DATA = 0x0101;
+
+ /**
+ * @var int
+ */
+ const XREF_MISSING = 0x0102;
+
+ /**
+ * @var int
+ */
+ const ENTRIES_TOO_LARGE = 0x0103;
+
+ /**
+ * @var int
+ */
+ const ENTRIES_TOO_SHORT = 0x0104;
+
+ /**
+ * @var int
+ */
+ const NO_ENTRIES = 0x0105;
+
+ /**
+ * @var int
+ */
+ const NO_TRAILER_FOUND = 0x0106;
+
+ /**
+ * @var int
+ */
+ const NO_STARTXREF_FOUND = 0x0107;
+
+ /**
+ * @var int
+ */
+ const NO_XREF_FOUND = 0x0108;
+
+ /**
+ * @var int
+ */
+ const UNEXPECTED_END = 0x0109;
+
+ /**
+ * @var int
+ */
+ const OBJECT_NOT_FOUND = 0x010A;
+
+ /**
+ * @var int
+ */
+ const COMPRESSED_XREF = 0x010B;
+
+ /**
+ * @var int
+ */
+ const ENCRYPTED = 0x010C;
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/CrossReference/FixedReader.php b/vendor/setasign/fpdi/src/PdfParser/CrossReference/FixedReader.php
new file mode 100644
index 0000000..883feec
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/CrossReference/FixedReader.php
@@ -0,0 +1,199 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\CrossReference;
+
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\StreamReader;
+
+/**
+ * Class FixedReader
+ *
+ * This reader allows a very less overhead parsing of single entries of the cross-reference, because the main entries
+ * are only read when needed and not in a single run.
+ */
+class FixedReader extends AbstractReader implements ReaderInterface
+{
+ /**
+ * @var StreamReader
+ */
+ protected $reader;
+
+ /**
+ * Data of subsections.
+ *
+ * @var array
+ */
+ protected $subSections;
+
+ /**
+ * FixedReader constructor.
+ *
+ * @param PdfParser $parser
+ * @throws CrossReferenceException
+ */
+ public function __construct(PdfParser $parser)
+ {
+ $this->reader = $parser->getStreamReader();
+ $this->read();
+ parent::__construct($parser);
+ }
+
+ /**
+ * Get all subsection data.
+ *
+ * @return array
+ */
+ public function getSubSections()
+ {
+ return $this->subSections;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getOffsetFor($objectNumber)
+ {
+ foreach ($this->subSections as $offset => list($startObject, $objectCount)) {
+ /**
+ * @var int $startObject
+ * @var int $objectCount
+ */
+ if ($objectNumber >= $startObject && $objectNumber < ($startObject + $objectCount)) {
+ $position = $offset + 20 * ($objectNumber - $startObject);
+ $this->reader->ensure($position, 20);
+ $line = $this->reader->readBytes(20);
+ if ($line[17] === 'f') {
+ return false;
+ }
+
+ return (int) \substr($line, 0, 10);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Read the cross-reference.
+ *
+ * This reader will only read the subsections in this method. The offsets were resolved individually by this
+ * information.
+ *
+ * @throws CrossReferenceException
+ */
+ protected function read()
+ {
+ $subSections = [];
+
+ $startObject = $entryCount = $lastLineStart = null;
+ $validityChecked = false;
+ while (($line = $this->reader->readLine(20)) !== false) {
+ if (\strpos($line, 'trailer') !== false) {
+ $this->reader->reset($lastLineStart);
+ break;
+ }
+
+ // jump over if line content doesn't match the expected string
+ if (\sscanf($line, '%d %d', $startObject, $entryCount) !== 2) {
+ continue;
+ }
+
+ $oldPosition = $this->reader->getPosition();
+ $position = $oldPosition + $this->reader->getOffset();
+
+ if (!$validityChecked && $entryCount > 0) {
+ $nextLine = $this->reader->readBytes(21);
+ /* Check the next line for maximum of 20 bytes and not longer
+ * By catching 21 bytes and trimming the length should be still 21.
+ */
+ if (\strlen(\trim($nextLine)) !== 21) {
+ throw new CrossReferenceException(
+ 'Cross-reference entries are larger than 20 bytes.',
+ CrossReferenceException::ENTRIES_TOO_LARGE
+ );
+ }
+
+ /* Check for less than 20 bytes: cut the line to 20 bytes and trim; have to result in exactly 18 bytes.
+ * If it would have less bytes the substring would get the first bytes of the next line which would
+ * evaluate to a 20 bytes long string after trimming.
+ */
+ if (\strlen(\trim(\substr($nextLine, 0, 20))) !== 18) {
+ throw new CrossReferenceException(
+ 'Cross-reference entries are less than 20 bytes.',
+ CrossReferenceException::ENTRIES_TOO_SHORT
+ );
+ }
+
+ $validityChecked = true;
+ }
+
+ $subSections[$position] = [$startObject, $entryCount];
+
+ $lastLineStart = $position + $entryCount * 20;
+ $this->reader->reset($lastLineStart);
+ }
+
+ // reset after the last correct parsed line
+ $this->reader->reset($lastLineStart);
+
+ if (\count($subSections) === 0) {
+ throw new CrossReferenceException(
+ 'No entries found in cross-reference.',
+ CrossReferenceException::NO_ENTRIES
+ );
+ }
+
+ $this->subSections = $subSections;
+ }
+
+ /**
+ * Fixes an invalid object number shift.
+ *
+ * This method can be used to repair documents with an invalid subsection header:
+ *
+ * <code>
+ * xref
+ * 1 7
+ * 0000000000 65535 f
+ * 0000000009 00000 n
+ * 0000412075 00000 n
+ * 0000412172 00000 n
+ * 0000412359 00000 n
+ * 0000412417 00000 n
+ * 0000412468 00000 n
+ * </code>
+ *
+ * It shall only be called on the first table.
+ *
+ * @return bool
+ */
+ public function fixFaultySubSectionShift()
+ {
+ $subSections = $this->getSubSections();
+ if (\count($subSections) > 1) {
+ return false;
+ }
+
+ $subSection = \current($subSections);
+ if ($subSection[0] != 1) {
+ return false;
+ }
+
+ if ($this->getOffsetFor(1) === false) {
+ foreach ($subSections as $offset => list($startObject, $objectCount)) {
+ $this->subSections[$offset] = [$startObject - 1, $objectCount];
+ }
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/CrossReference/LineReader.php b/vendor/setasign/fpdi/src/PdfParser/CrossReference/LineReader.php
new file mode 100644
index 0000000..b6f0e42
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/CrossReference/LineReader.php
@@ -0,0 +1,167 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\CrossReference;
+
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\StreamReader;
+
+/**
+ * Class LineReader
+ *
+ * This reader class read all cross-reference entries in a single run.
+ * It supports reading cross-references with e.g. invalid data (e.g. entries with a length < or > 20 bytes).
+ */
+class LineReader extends AbstractReader implements ReaderInterface
+{
+ /**
+ * The object offsets.
+ *
+ * @var array
+ */
+ protected $offsets;
+
+ /**
+ * LineReader constructor.
+ *
+ * @param PdfParser $parser
+ * @throws CrossReferenceException
+ */
+ public function __construct(PdfParser $parser)
+ {
+ $this->read($this->extract($parser->getStreamReader()));
+ parent::__construct($parser);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getOffsetFor($objectNumber)
+ {
+ if (isset($this->offsets[$objectNumber])) {
+ return $this->offsets[$objectNumber][0];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get all found offsets.
+ *
+ * @return array
+ */
+ public function getOffsets()
+ {
+ return $this->offsets;
+ }
+
+ /**
+ * Extracts the cross reference data from the stream reader.
+ *
+ * @param StreamReader $reader
+ * @return string
+ * @throws CrossReferenceException
+ */
+ protected function extract(StreamReader $reader)
+ {
+ $bytesPerCycle = 100;
+ $reader->reset(null, $bytesPerCycle);
+
+ $cycles = 0;
+ do {
+ // 6 = length of "trailer" - 1
+ $pos = \max(($bytesPerCycle * $cycles) - 6, 0);
+ $trailerPos = \strpos($reader->getBuffer(false), 'trailer', $pos);
+ $cycles++;
+ } while ($trailerPos === false && $reader->increaseLength($bytesPerCycle) !== false);
+
+ if ($trailerPos === false) {
+ throw new CrossReferenceException(
+ 'Unexpected end of cross reference. "trailer"-keyword not found.',
+ CrossReferenceException::NO_TRAILER_FOUND
+ );
+ }
+
+ $xrefContent = \substr($reader->getBuffer(false), 0, $trailerPos);
+ $reader->reset($reader->getPosition() + $trailerPos);
+
+ return $xrefContent;
+ }
+
+ /**
+ * Read the cross-reference entries.
+ *
+ * @param string $xrefContent
+ * @throws CrossReferenceException
+ */
+ protected function read($xrefContent)
+ {
+ // get eol markers in the first 100 bytes
+ \preg_match_all("/(\r\n|\n|\r)/", \substr($xrefContent, 0, 100), $m);
+
+ if (\count($m[0]) === 0) {
+ throw new CrossReferenceException(
+ 'No data found in cross-reference.',
+ CrossReferenceException::INVALID_DATA
+ );
+ }
+
+ // count(array_count_values()) is faster then count(array_unique())
+ // @see https://github.com/symfony/symfony/pull/23731
+ // can be reverted for php7.2
+ $differentLineEndings = \count(\array_count_values($m[0]));
+ if ($differentLineEndings > 1) {
+ $lines = \preg_split("/(\r\n|\n|\r)/", $xrefContent, -1, PREG_SPLIT_NO_EMPTY);
+ } else {
+ $lines = \explode($m[0][0], $xrefContent);
+ }
+
+ unset($differentLineEndings, $m);
+ if (!\is_array($lines)) {
+ $this->offsets = [];
+ return;
+ }
+
+ $start = 0;
+ $offsets = [];
+
+ // trim all lines and remove empty lines
+ $lines = \array_filter(\array_map('\trim', $lines));
+ foreach ($lines as $line) {
+ $pieces = \explode(' ', $line);
+
+ switch (\count($pieces)) {
+ case 2:
+ $start = (int) $pieces[0];
+ break;
+
+ case 3:
+ switch ($pieces[2]) {
+ case 'n':
+ $offsets[$start] = [(int) $pieces[0], (int) $pieces[1]];
+ $start++;
+ break 2;
+ case 'f':
+ $start++;
+ break 2;
+ }
+ // fall through if pieces doesn't match
+
+ default:
+ throw new CrossReferenceException(
+ \sprintf('Unexpected data in xref table (%s)', \implode(' ', $pieces)),
+ CrossReferenceException::INVALID_DATA
+ );
+ }
+ }
+
+ $this->offsets = $offsets;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/CrossReference/ReaderInterface.php b/vendor/setasign/fpdi/src/PdfParser/CrossReference/ReaderInterface.php
new file mode 100644
index 0000000..d2dfdd0
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/CrossReference/ReaderInterface.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\CrossReference;
+
+use setasign\Fpdi\PdfParser\Type\PdfDictionary;
+
+/**
+ * ReaderInterface for cross-reference readers.
+ */
+interface ReaderInterface
+{
+ /**
+ * Get an offset by an object number.
+ *
+ * @param int $objectNumber
+ * @return int|bool False if the offset was not found.
+ */
+ public function getOffsetFor($objectNumber);
+
+ /**
+ * Get the trailer related to this cross reference.
+ *
+ * @return PdfDictionary
+ */
+ public function getTrailer();
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Filter/Ascii85.php b/vendor/setasign/fpdi/src/PdfParser/Filter/Ascii85.php
new file mode 100644
index 0000000..1dc936d
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Filter/Ascii85.php
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Filter;
+
+/**
+ * Class for handling ASCII base-85 encoded data
+ */
+class Ascii85 implements FilterInterface
+{
+ /**
+ * Decode ASCII85 encoded string.
+ *
+ * @param string $data The input string
+ * @return string
+ * @throws Ascii85Exception
+ */
+ public function decode($data)
+ {
+ $out = '';
+ $state = 0;
+ $chn = null;
+
+ $data = \preg_replace('/\s/', '', $data);
+
+ $l = \strlen($data);
+
+ /** @noinspection ForeachInvariantsInspection */
+ for ($k = 0; $k < $l; ++$k) {
+ $ch = \ord($data[$k]) & 0xff;
+
+ //Start <~
+ if ($k === 0 && $ch === 60 && isset($data[$k + 1]) && (\ord($data[$k + 1]) & 0xFF) === 126) {
+ $k++;
+ continue;
+ }
+ //End ~>
+ if ($ch === 126 && isset($data[$k + 1]) && (\ord($data[$k + 1]) & 0xFF) === 62) {
+ break;
+ }
+
+ if ($ch === 122 /* z */ && $state === 0) {
+ $out .= \chr(0) . \chr(0) . \chr(0) . \chr(0);
+ continue;
+ }
+
+ if ($ch < 33 /* ! */ || $ch > 117 /* u */) {
+ throw new Ascii85Exception(
+ 'Illegal character found while ASCII85 decode.',
+ Ascii85Exception::ILLEGAL_CHAR_FOUND
+ );
+ }
+
+ $chn[$state] = $ch - 33;/* ! */
+ $state++;
+
+ if ($state === 5) {
+ $state = 0;
+ $r = 0;
+ for ($j = 0; $j < 5; ++$j) {
+ /** @noinspection UnnecessaryCastingInspection */
+ $r = (int)($r * 85 + $chn[$j]);
+ }
+
+ $out .= \chr($r >> 24)
+ . \chr($r >> 16)
+ . \chr($r >> 8)
+ . \chr($r);
+ }
+ }
+
+ if ($state === 1) {
+ throw new Ascii85Exception(
+ 'Illegal length while ASCII85 decode.',
+ Ascii85Exception::ILLEGAL_LENGTH
+ );
+ }
+
+ if ($state === 2) {
+ $r = $chn[0] * 85 * 85 * 85 * 85 + ($chn[1] + 1) * 85 * 85 * 85;
+ $out .= \chr($r >> 24);
+ } elseif ($state === 3) {
+ $r = $chn[0] * 85 * 85 * 85 * 85 + $chn[1] * 85 * 85 * 85 + ($chn[2] + 1) * 85 * 85;
+ $out .= \chr($r >> 24);
+ $out .= \chr($r >> 16);
+ } elseif ($state === 4) {
+ $r = $chn[0] * 85 * 85 * 85 * 85 + $chn[1] * 85 * 85 * 85 + $chn[2] * 85 * 85 + ($chn[3] + 1) * 85;
+ $out .= \chr($r >> 24);
+ $out .= \chr($r >> 16);
+ $out .= \chr($r >> 8);
+ }
+
+ return $out;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Filter/Ascii85Exception.php b/vendor/setasign/fpdi/src/PdfParser/Filter/Ascii85Exception.php
new file mode 100644
index 0000000..f4b6758
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Filter/Ascii85Exception.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Filter;
+
+/**
+ * Exception for Ascii85 filter class
+ */
+class Ascii85Exception extends FilterException
+{
+ /**
+ * @var integer
+ */
+ const ILLEGAL_CHAR_FOUND = 0x0301;
+
+ /**
+ * @var integer
+ */
+ const ILLEGAL_LENGTH = 0x0302;
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Filter/AsciiHex.php b/vendor/setasign/fpdi/src/PdfParser/Filter/AsciiHex.php
new file mode 100644
index 0000000..d0c3436
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Filter/AsciiHex.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Filter;
+
+/**
+ * Class for handling ASCII hexadecimal encoded data
+ */
+class AsciiHex implements FilterInterface
+{
+ /**
+ * Converts an ASCII hexadecimal encoded string into its binary representation.
+ *
+ * @param string $data The input string
+ * @return string
+ */
+ public function decode($data)
+ {
+ $data = \preg_replace('/[^0-9A-Fa-f]/', '', \rtrim($data, '>'));
+ if ((\strlen($data) % 2) === 1) {
+ $data .= '0';
+ }
+
+ return \pack('H*', $data);
+ }
+
+ /**
+ * Converts a string into ASCII hexadecimal representation.
+ *
+ * @param string $data The input string
+ * @param boolean $leaveEOD
+ * @return string
+ */
+ public function encode($data, $leaveEOD = false)
+ {
+ $t = \unpack('H*', $data);
+ return \current($t)
+ . ($leaveEOD ? '' : '>');
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Filter/FilterException.php b/vendor/setasign/fpdi/src/PdfParser/Filter/FilterException.php
new file mode 100644
index 0000000..c55a7a8
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Filter/FilterException.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Filter;
+
+use setasign\Fpdi\PdfParser\PdfParserException;
+
+/**
+ * Exception for filters
+ */
+class FilterException extends PdfParserException
+{
+ const UNSUPPORTED_FILTER = 0x0201;
+
+ const NOT_IMPLEMENTED = 0x0202;
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Filter/FilterInterface.php b/vendor/setasign/fpdi/src/PdfParser/Filter/FilterInterface.php
new file mode 100644
index 0000000..3700190
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Filter/FilterInterface.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Filter;
+
+/**
+ * Interface for filters
+ */
+interface FilterInterface
+{
+ /**
+ * Decode a string.
+ *
+ * @param string $data The input string
+ * @return string
+ */
+ public function decode($data);
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Filter/Flate.php b/vendor/setasign/fpdi/src/PdfParser/Filter/Flate.php
new file mode 100644
index 0000000..b8f79d1
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Filter/Flate.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Filter;
+
+/**
+ * Class for handling zlib/deflate encoded data
+ */
+class Flate implements FilterInterface
+{
+ /**
+ * Checks whether the zlib extension is loaded.
+ *
+ * Used for testing purpose.
+ *
+ * @return boolean
+ * @internal
+ */
+ protected function extensionLoaded()
+ {
+ return \extension_loaded('zlib');
+ }
+
+ /**
+ * Decodes a flate compressed string.
+ *
+ * @param string|false $data The input string
+ * @return string
+ * @throws FlateException
+ */
+ public function decode($data)
+ {
+ if ($this->extensionLoaded()) {
+ $oData = $data;
+ $data = (($data !== '') ? @\gzuncompress($data) : '');
+ if ($data === false) {
+ // let's try if the checksum is CRC32
+ $fh = fopen('php://temp', 'w+b');
+ fwrite($fh, "\x1f\x8b\x08\x00\x00\x00\x00\x00" . $oData);
+ stream_filter_append($fh, 'zlib.inflate', STREAM_FILTER_READ, ['window' => 30]);
+ fseek($fh, 0);
+ $data = @stream_get_contents($fh);
+ fclose($fh);
+
+ if ($data) {
+ return $data;
+ }
+
+ // Try this fallback
+ $tries = 0;
+
+ $oDataLen = strlen($oData);
+ while ($tries < 6 && ($data === false || (strlen($data) < ($oDataLen - $tries - 1)))) {
+ $data = @(gzinflate(substr($oData, $tries)));
+ $tries++;
+ }
+
+ // let's use this fallback only if the $data is longer than the original data
+ if (strlen($data) > ($oDataLen - $tries - 1)) {
+ return $data;
+ }
+
+ if (!$data) {
+ throw new FlateException(
+ 'Error while decompressing stream.',
+ FlateException::DECOMPRESS_ERROR
+ );
+ }
+ }
+ } else {
+ throw new FlateException(
+ 'To handle FlateDecode filter, enable zlib support in PHP.',
+ FlateException::NO_ZLIB
+ );
+ }
+
+ return $data;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Filter/FlateException.php b/vendor/setasign/fpdi/src/PdfParser/Filter/FlateException.php
new file mode 100644
index 0000000..d897ac8
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Filter/FlateException.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Filter;
+
+/**
+ * Exception for flate filter class
+ */
+class FlateException extends FilterException
+{
+ /**
+ * @var integer
+ */
+ const NO_ZLIB = 0x0401;
+
+ /**
+ * @var integer
+ */
+ const DECOMPRESS_ERROR = 0x0402;
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Filter/Lzw.php b/vendor/setasign/fpdi/src/PdfParser/Filter/Lzw.php
new file mode 100644
index 0000000..bedb5b7
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Filter/Lzw.php
@@ -0,0 +1,187 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Filter;
+
+/**
+ * Class for handling LZW encoded data
+ */
+class Lzw implements FilterInterface
+{
+ /**
+ * @var null|string
+ */
+ protected $data;
+
+ /**
+ * @var array
+ */
+ protected $sTable = [];
+
+ /**
+ * @var int
+ */
+ protected $dataLength = 0;
+
+ /**
+ * @var int
+ */
+ protected $tIdx;
+
+ /**
+ * @var int
+ */
+ protected $bitsToGet = 9;
+
+ /**
+ * @var int
+ */
+ protected $bytePointer;
+
+ /**
+ * @var int
+ */
+ protected $nextData = 0;
+
+ /**
+ * @var int
+ */
+ protected $nextBits = 0;
+
+ /**
+ * @var array
+ */
+ protected $andTable = [511, 1023, 2047, 4095];
+
+ /**
+ * Method to decode LZW compressed data.
+ *
+ * @param string $data The compressed data
+ * @return string The uncompressed data
+ * @throws LzwException
+ */
+ public function decode($data)
+ {
+ if ($data[0] === "\x00" && $data[1] === "\x01") {
+ throw new LzwException(
+ 'LZW flavour not supported.',
+ LzwException::LZW_FLAVOUR_NOT_SUPPORTED
+ );
+ }
+
+ $this->initsTable();
+
+ $this->data = $data;
+ $this->dataLength = \strlen($data);
+
+ // Initialize pointers
+ $this->bytePointer = 0;
+
+ $this->nextData = 0;
+ $this->nextBits = 0;
+
+ $oldCode = 0;
+
+ $uncompData = '';
+
+ while (($code = $this->getNextCode()) !== 257) {
+ if ($code === 256) {
+ $this->initsTable();
+ $code = $this->getNextCode();
+
+ if ($code === 257) {
+ break;
+ }
+
+ $uncompData .= $this->sTable[$code];
+ $oldCode = $code;
+ } else {
+ if ($code < $this->tIdx) {
+ $string = $this->sTable[$code];
+ $uncompData .= $string;
+
+ $this->addStringToTable($this->sTable[$oldCode], $string[0]);
+ $oldCode = $code;
+ } else {
+ $string = $this->sTable[$oldCode];
+ $string .= $string[0];
+ $uncompData .= $string;
+
+ $this->addStringToTable($string);
+ $oldCode = $code;
+ }
+ }
+ }
+
+ return $uncompData;
+ }
+
+ /**
+ * Initialize the string table.
+ */
+ protected function initsTable()
+ {
+ $this->sTable = [];
+
+ for ($i = 0; $i < 256; $i++) {
+ $this->sTable[$i] = \chr($i);
+ }
+
+ $this->tIdx = 258;
+ $this->bitsToGet = 9;
+ }
+
+ /**
+ * Add a new string to the string table.
+ *
+ * @param string $oldString
+ * @param string $newString
+ */
+ protected function addStringToTable($oldString, $newString = '')
+ {
+ $string = $oldString . $newString;
+
+ // Add this new String to the table
+ $this->sTable[$this->tIdx++] = $string;
+
+ if ($this->tIdx === 511) {
+ $this->bitsToGet = 10;
+ } elseif ($this->tIdx === 1023) {
+ $this->bitsToGet = 11;
+ } elseif ($this->tIdx === 2047) {
+ $this->bitsToGet = 12;
+ }
+ }
+
+ /**
+ * Returns the next 9, 10, 11 or 12 bits.
+ *
+ * @return integer
+ */
+ protected function getNextCode()
+ {
+ if ($this->bytePointer === $this->dataLength) {
+ return 257;
+ }
+
+ $this->nextData = ($this->nextData << 8) | (\ord($this->data[$this->bytePointer++]) & 0xff);
+ $this->nextBits += 8;
+
+ if ($this->nextBits < $this->bitsToGet) {
+ $this->nextData = ($this->nextData << 8) | (\ord($this->data[$this->bytePointer++]) & 0xff);
+ $this->nextBits += 8;
+ }
+
+ $code = ($this->nextData >> ($this->nextBits - $this->bitsToGet)) & $this->andTable[$this->bitsToGet - 9];
+ $this->nextBits -= $this->bitsToGet;
+
+ return $code;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Filter/LzwException.php b/vendor/setasign/fpdi/src/PdfParser/Filter/LzwException.php
new file mode 100644
index 0000000..6ebad4f
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Filter/LzwException.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Filter;
+
+/**
+ * Exception for LZW filter class
+ */
+class LzwException extends FilterException
+{
+ /**
+ * @var integer
+ */
+ const LZW_FLAVOUR_NOT_SUPPORTED = 0x0501;
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/PdfParser.php b/vendor/setasign/fpdi/src/PdfParser/PdfParser.php
new file mode 100644
index 0000000..f724314
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/PdfParser.php
@@ -0,0 +1,381 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser;
+
+use setasign\Fpdi\PdfParser\CrossReference\CrossReference;
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+use setasign\Fpdi\PdfParser\Type\PdfArray;
+use setasign\Fpdi\PdfParser\Type\PdfBoolean;
+use setasign\Fpdi\PdfParser\Type\PdfDictionary;
+use setasign\Fpdi\PdfParser\Type\PdfHexString;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObjectReference;
+use setasign\Fpdi\PdfParser\Type\PdfName;
+use setasign\Fpdi\PdfParser\Type\PdfNull;
+use setasign\Fpdi\PdfParser\Type\PdfNumeric;
+use setasign\Fpdi\PdfParser\Type\PdfStream;
+use setasign\Fpdi\PdfParser\Type\PdfString;
+use setasign\Fpdi\PdfParser\Type\PdfToken;
+use setasign\Fpdi\PdfParser\Type\PdfType;
+
+/**
+ * A PDF parser class
+ */
+class PdfParser
+{
+ /**
+ * @var StreamReader
+ */
+ protected $streamReader;
+
+ /**
+ * @var Tokenizer
+ */
+ protected $tokenizer;
+
+ /**
+ * The file header.
+ *
+ * @var string
+ */
+ protected $fileHeader;
+
+ /**
+ * The offset to the file header.
+ *
+ * @var int
+ */
+ protected $fileHeaderOffset;
+
+ /**
+ * @var CrossReference|null
+ */
+ protected $xref;
+
+ /**
+ * All read objects.
+ *
+ * @var array
+ */
+ protected $objects = [];
+
+ /**
+ * PdfParser constructor.
+ *
+ * @param StreamReader $streamReader
+ */
+ public function __construct(StreamReader $streamReader)
+ {
+ $this->streamReader = $streamReader;
+ $this->tokenizer = new Tokenizer($streamReader);
+ }
+
+ /**
+ * Removes cycled references.
+ *
+ * @internal
+ */
+ public function cleanUp()
+ {
+ $this->xref = null;
+ }
+
+ /**
+ * Get the stream reader instance.
+ *
+ * @return StreamReader
+ */
+ public function getStreamReader()
+ {
+ return $this->streamReader;
+ }
+
+ /**
+ * Get the tokenizer instance.
+ *
+ * @return Tokenizer
+ */
+ public function getTokenizer()
+ {
+ return $this->tokenizer;
+ }
+
+ /**
+ * Resolves the file header.
+ *
+ * @throws PdfParserException
+ * @return int
+ */
+ protected function resolveFileHeader()
+ {
+ if ($this->fileHeader) {
+ return $this->fileHeaderOffset;
+ }
+
+ $this->streamReader->reset(0);
+ $maxIterations = 1000;
+ while (true) {
+ $buffer = $this->streamReader->getBuffer(false);
+ $offset = \strpos($buffer, '%PDF-');
+ if ($offset === false) {
+ if (!$this->streamReader->increaseLength(100) || (--$maxIterations === 0)) {
+ throw new PdfParserException(
+ 'Unable to find PDF file header.',
+ PdfParserException::FILE_HEADER_NOT_FOUND
+ );
+ }
+ continue;
+ }
+ break;
+ }
+
+ $this->fileHeaderOffset = $offset;
+ $this->streamReader->setOffset($offset);
+
+ $this->fileHeader = \trim($this->streamReader->readLine());
+ return $this->fileHeaderOffset;
+ }
+
+ /**
+ * Get the cross reference instance.
+ *
+ * @return CrossReference
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ public function getCrossReference()
+ {
+ if ($this->xref === null) {
+ $this->xref = new CrossReference($this, $this->resolveFileHeader());
+ }
+
+ return $this->xref;
+ }
+
+ /**
+ * Get the PDF version.
+ *
+ * @return int[] An array of major and minor version.
+ * @throws PdfParserException
+ */
+ public function getPdfVersion()
+ {
+ $this->resolveFileHeader();
+
+ if (\preg_match('/%PDF-(\d)\.(\d)/', $this->fileHeader, $result) === 0) {
+ throw new PdfParserException(
+ 'Unable to extract PDF version from file header.',
+ PdfParserException::PDF_VERSION_NOT_FOUND
+ );
+ }
+ list(, $major, $minor) = $result;
+
+ $catalog = $this->getCatalog();
+ if (isset($catalog->value['Version'])) {
+ $versionParts = \explode(
+ '.',
+ PdfName::unescape(PdfType::resolve($catalog->value['Version'], $this)->value)
+ );
+ if (count($versionParts) === 2) {
+ list($major, $minor) = $versionParts;
+ }
+ }
+
+ return [(int) $major, (int) $minor];
+ }
+
+ /**
+ * Get the catalog dictionary.
+ *
+ * @return PdfDictionary
+ * @throws Type\PdfTypeException
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ public function getCatalog()
+ {
+ $trailer = $this->getCrossReference()->getTrailer();
+
+ $catalog = PdfType::resolve(PdfDictionary::get($trailer, 'Root'), $this);
+
+ return PdfDictionary::ensure($catalog);
+ }
+
+ /**
+ * Get an indirect object by its object number.
+ *
+ * @param int $objectNumber
+ * @param bool $cache
+ * @return PdfIndirectObject
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ public function getIndirectObject($objectNumber, $cache = false)
+ {
+ $objectNumber = (int) $objectNumber;
+ if (isset($this->objects[$objectNumber])) {
+ return $this->objects[$objectNumber];
+ }
+
+ $object = $this->getCrossReference()->getIndirectObject($objectNumber);
+
+ if ($cache) {
+ $this->objects[$objectNumber] = $object;
+ }
+
+ return $object;
+ }
+
+ /**
+ * Read a PDF value.
+ *
+ * @param null|bool|string $token
+ * @param null|string $expectedType
+ * @return false|PdfArray|PdfBoolean|PdfDictionary|PdfHexString|PdfIndirectObject|PdfIndirectObjectReference|PdfName|PdfNull|PdfNumeric|PdfStream|PdfString|PdfToken
+ * @throws Type\PdfTypeException
+ */
+ public function readValue($token = null, $expectedType = null)
+ {
+ if ($token === null) {
+ $token = $this->tokenizer->getNextToken();
+ }
+
+ if ($token === false) {
+ if ($expectedType !== null) {
+ throw new Type\PdfTypeException('Got unexpected token type.', Type\PdfTypeException::INVALID_DATA_TYPE);
+ }
+ return false;
+ }
+
+ switch ($token) {
+ case '(':
+ $this->ensureExpectedType($token, $expectedType);
+ return PdfString::parse($this->streamReader);
+
+ case '<':
+ if ($this->streamReader->getByte() === '<') {
+ $this->ensureExpectedType('<<', $expectedType);
+ $this->streamReader->addOffset(1);
+ return PdfDictionary::parse($this->tokenizer, $this->streamReader, $this);
+ }
+
+ $this->ensureExpectedType($token, $expectedType);
+ return PdfHexString::parse($this->streamReader);
+
+ case '/':
+ $this->ensureExpectedType($token, $expectedType);
+ return PdfName::parse($this->tokenizer, $this->streamReader);
+
+ case '[':
+ $this->ensureExpectedType($token, $expectedType);
+ return PdfArray::parse($this->tokenizer, $this);
+
+ default:
+ if (\is_numeric($token)) {
+ if (($token2 = $this->tokenizer->getNextToken()) !== false) {
+ if (\is_numeric($token2) && ($token3 = $this->tokenizer->getNextToken()) !== false) {
+ switch ($token3) {
+ case 'obj':
+ if ($expectedType !== null && $expectedType !== PdfIndirectObject::class) {
+ throw new Type\PdfTypeException(
+ 'Got unexpected token type.',
+ Type\PdfTypeException::INVALID_DATA_TYPE
+ );
+ }
+
+ return PdfIndirectObject::parse(
+ (int) $token,
+ (int) $token2,
+ $this,
+ $this->tokenizer,
+ $this->streamReader
+ );
+ case 'R':
+ if (
+ $expectedType !== null &&
+ $expectedType !== PdfIndirectObjectReference::class
+ ) {
+ throw new Type\PdfTypeException(
+ 'Got unexpected token type.',
+ Type\PdfTypeException::INVALID_DATA_TYPE
+ );
+ }
+
+ return PdfIndirectObjectReference::create((int) $token, (int) $token2);
+ }
+
+ $this->tokenizer->pushStack($token3);
+ }
+
+ $this->tokenizer->pushStack($token2);
+ }
+
+ if ($expectedType !== null && $expectedType !== PdfNumeric::class) {
+ throw new Type\PdfTypeException(
+ 'Got unexpected token type.',
+ Type\PdfTypeException::INVALID_DATA_TYPE
+ );
+ }
+ return PdfNumeric::create($token + 0);
+ }
+
+ if ($token === 'true' || $token === 'false') {
+ $this->ensureExpectedType($token, $expectedType);
+ return PdfBoolean::create($token === 'true');
+ }
+
+ if ($token === 'null') {
+ $this->ensureExpectedType($token, $expectedType);
+ return new PdfNull();
+ }
+
+ if ($expectedType !== null && $expectedType !== PdfToken::class) {
+ throw new Type\PdfTypeException(
+ 'Got unexpected token type.',
+ Type\PdfTypeException::INVALID_DATA_TYPE
+ );
+ }
+
+ $v = new PdfToken();
+ $v->value = $token;
+
+ return $v;
+ }
+ }
+
+ /**
+ * Ensures that the token will evaluate to an expected object type (or not).
+ *
+ * @param string $token
+ * @param string|null $expectedType
+ * @return bool
+ * @throws Type\PdfTypeException
+ */
+ private function ensureExpectedType($token, $expectedType)
+ {
+ static $mapping = [
+ '(' => PdfString::class,
+ '<' => PdfHexString::class,
+ '<<' => PdfDictionary::class,
+ '/' => PdfName::class,
+ '[' => PdfArray::class,
+ 'true' => PdfBoolean::class,
+ 'false' => PdfBoolean::class,
+ 'null' => PdfNull::class
+ ];
+
+ if ($expectedType === null || $mapping[$token] === $expectedType) {
+ return true;
+ }
+
+ throw new Type\PdfTypeException('Got unexpected token type.', Type\PdfTypeException::INVALID_DATA_TYPE);
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/PdfParserException.php b/vendor/setasign/fpdi/src/PdfParser/PdfParserException.php
new file mode 100644
index 0000000..6d034d8
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/PdfParserException.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser;
+
+use setasign\Fpdi\FpdiException;
+
+/**
+ * Exception for the pdf parser class
+ */
+class PdfParserException extends FpdiException
+{
+ /**
+ * @var int
+ */
+ const NOT_IMPLEMENTED = 0x0001;
+
+ /**
+ * @var int
+ */
+ const IMPLEMENTED_IN_FPDI_PDF_PARSER = 0x0002;
+
+ /**
+ * @var int
+ */
+ const INVALID_DATA_TYPE = 0x0003;
+
+ /**
+ * @var int
+ */
+ const FILE_HEADER_NOT_FOUND = 0x0004;
+
+ /**
+ * @var int
+ */
+ const PDF_VERSION_NOT_FOUND = 0x0005;
+
+ /**
+ * @var int
+ */
+ const INVALID_DATA_SIZE = 0x0006;
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/StreamReader.php b/vendor/setasign/fpdi/src/PdfParser/StreamReader.php
new file mode 100644
index 0000000..ee40ebb
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/StreamReader.php
@@ -0,0 +1,471 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser;
+
+/**
+ * A stream reader class
+ */
+class StreamReader
+{
+ /**
+ * Creates a stream reader instance by a string value.
+ *
+ * @param string $content
+ * @param int $maxMemory
+ * @return StreamReader
+ */
+ public static function createByString($content, $maxMemory = 2097152)
+ {
+ $h = \fopen('php://temp/maxmemory:' . ((int) $maxMemory), 'r+b');
+ \fwrite($h, $content);
+ \rewind($h);
+
+ return new self($h, true);
+ }
+
+ /**
+ * Creates a stream reader instance by a filename.
+ *
+ * @param string $filename
+ * @return StreamReader
+ */
+ public static function createByFile($filename)
+ {
+ $h = \fopen($filename, 'rb');
+ return new self($h, true);
+ }
+
+ /**
+ * Defines whether the stream should be closed when the stream reader instance is deconstructed or not.
+ *
+ * @var bool
+ */
+ protected $closeStream;
+
+ /**
+ * The stream resource.
+ *
+ * @var resource
+ */
+ protected $stream;
+
+ /**
+ * The byte-offset position in the stream.
+ *
+ * @var int
+ */
+ protected $position;
+
+ /**
+ * The byte-offset position in the buffer.
+ *
+ * @var int
+ */
+ protected $offset;
+
+ /**
+ * The buffer length.
+ *
+ * @var int
+ */
+ protected $bufferLength;
+
+ /**
+ * The total length of the stream.
+ *
+ * @var int
+ */
+ protected $totalLength;
+
+ /**
+ * The buffer.
+ *
+ * @var string
+ */
+ protected $buffer;
+
+ /**
+ * StreamReader constructor.
+ *
+ * @param resource $stream
+ * @param bool $closeStream Defines whether to close the stream resource if the instance is destructed or not.
+ */
+ public function __construct($stream, $closeStream = false)
+ {
+ if (!\is_resource($stream)) {
+ throw new \InvalidArgumentException(
+ 'No stream given.'
+ );
+ }
+
+ $metaData = \stream_get_meta_data($stream);
+ if (!$metaData['seekable']) {
+ throw new \InvalidArgumentException(
+ 'Given stream is not seekable!'
+ );
+ }
+
+ $this->stream = $stream;
+ $this->closeStream = $closeStream;
+ $this->reset();
+ }
+
+ /**
+ * The destructor.
+ */
+ public function __destruct()
+ {
+ $this->cleanUp();
+ }
+
+ /**
+ * Closes the file handle.
+ */
+ public function cleanUp()
+ {
+ if ($this->closeStream && is_resource($this->stream)) {
+ \fclose($this->stream);
+ }
+ }
+
+ /**
+ * Returns the byte length of the buffer.
+ *
+ * @param bool $atOffset
+ * @return int
+ */
+ public function getBufferLength($atOffset = false)
+ {
+ if ($atOffset === false) {
+ return $this->bufferLength;
+ }
+
+ return $this->bufferLength - $this->offset;
+ }
+
+ /**
+ * Get the current position in the stream.
+ *
+ * @return int
+ */
+ public function getPosition()
+ {
+ return $this->position;
+ }
+
+ /**
+ * Returns the current buffer.
+ *
+ * @param bool $atOffset
+ * @return string
+ */
+ public function getBuffer($atOffset = true)
+ {
+ if ($atOffset === false) {
+ return $this->buffer;
+ }
+
+ $string = \substr($this->buffer, $this->offset);
+
+ return (string) $string;
+ }
+
+ /**
+ * Gets a byte at a specific position in the buffer.
+ *
+ * If the position is invalid the method will return false.
+ *
+ * If the $position parameter is set to null the value of $this->offset will be used.
+ *
+ * @param int|null $position
+ * @return string|bool
+ */
+ public function getByte($position = null)
+ {
+ $position = (int) ($position !== null ? $position : $this->offset);
+ if (
+ $position >= $this->bufferLength
+ && (!$this->increaseLength() || $position >= $this->bufferLength)
+ ) {
+ return false;
+ }
+
+ return $this->buffer[$position];
+ }
+
+ /**
+ * Returns a byte at a specific position, and set the offset to the next byte position.
+ *
+ * If the position is invalid the method will return false.
+ *
+ * If the $position parameter is set to null the value of $this->offset will be used.
+ *
+ * @param int|null $position
+ * @return string|bool
+ */
+ public function readByte($position = null)
+ {
+ if ($position !== null) {
+ $position = (int) $position;
+ // check if needed bytes are available in the current buffer
+ if (!($position >= $this->position && $position < $this->position + $this->bufferLength)) {
+ $this->reset($position);
+ $offset = $this->offset;
+ } else {
+ $offset = $position - $this->position;
+ }
+ } else {
+ $offset = $this->offset;
+ }
+
+ if (
+ $offset >= $this->bufferLength
+ && ((!$this->increaseLength()) || $offset >= $this->bufferLength)
+ ) {
+ return false;
+ }
+
+ $this->offset = $offset + 1;
+ return $this->buffer[$offset];
+ }
+
+ /**
+ * Read bytes from the current or a specific offset position and set the internal pointer to the next byte.
+ *
+ * If the position is invalid the method will return false.
+ *
+ * If the $position parameter is set to null the value of $this->offset will be used.
+ *
+ * @param int $length
+ * @param int|null $position
+ * @return string|false
+ */
+ public function readBytes($length, $position = null)
+ {
+ $length = (int) $length;
+ if ($position !== null) {
+ // check if needed bytes are available in the current buffer
+ if (!($position >= $this->position && $position < $this->position + $this->bufferLength)) {
+ $this->reset($position, $length);
+ $offset = $this->offset;
+ } else {
+ $offset = $position - $this->position;
+ }
+ } else {
+ $offset = $this->offset;
+ }
+
+ if (
+ ($offset + $length) > $this->bufferLength
+ && ((!$this->increaseLength($length)) || ($offset + $length) > $this->bufferLength)
+ ) {
+ return false;
+ }
+
+ $bytes = \substr($this->buffer, $offset, $length);
+ $this->offset = $offset + $length;
+
+ return $bytes;
+ }
+
+ /**
+ * Read a line from the current position.
+ *
+ * @param int $length
+ * @return string|bool
+ */
+ public function readLine($length = 1024)
+ {
+ if ($this->ensureContent() === false) {
+ return false;
+ }
+
+ $line = '';
+ while ($this->ensureContent()) {
+ $char = $this->readByte();
+
+ if ($char === "\n") {
+ break;
+ }
+
+ if ($char === "\r") {
+ if ($this->getByte() === "\n") {
+ $this->addOffset(1);
+ }
+ break;
+ }
+
+ $line .= $char;
+
+ if (\strlen($line) >= $length) {
+ break;
+ }
+ }
+
+ return $line;
+ }
+
+ /**
+ * Set the offset position in the current buffer.
+ *
+ * @param int $offset
+ */
+ public function setOffset($offset)
+ {
+ if ($offset > $this->bufferLength || $offset < 0) {
+ throw new \OutOfRangeException(
+ \sprintf('Offset (%s) out of range (length: %s)', $offset, $this->bufferLength)
+ );
+ }
+
+ $this->offset = (int) $offset;
+ }
+
+ /**
+ * Returns the current offset in the current buffer.
+ *
+ * @return int
+ */
+ public function getOffset()
+ {
+ return $this->offset;
+ }
+
+ /**
+ * Add an offset to the current offset.
+ *
+ * @param int $offset
+ */
+ public function addOffset($offset)
+ {
+ $this->setOffset($this->offset + $offset);
+ }
+
+ /**
+ * Make sure that there is at least one character beyond the current offset in the buffer.
+ *
+ * @return bool
+ */
+ public function ensureContent()
+ {
+ while ($this->offset >= $this->bufferLength) {
+ if (!$this->increaseLength()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the stream.
+ *
+ * @return resource
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+
+ /**
+ * Gets the total available length.
+ *
+ * @return int
+ */
+ public function getTotalLength()
+ {
+ if ($this->totalLength === null) {
+ $stat = \fstat($this->stream);
+ $this->totalLength = $stat['size'];
+ }
+
+ return $this->totalLength;
+ }
+
+ /**
+ * Resets the buffer to a position and re-read the buffer with the given length.
+ *
+ * If the $pos parameter is negative the start buffer position will be the $pos'th position from
+ * the end of the file.
+ *
+ * If the $pos parameter is negative and the absolute value is bigger then the totalLength of
+ * the file $pos will set to zero.
+ *
+ * @param int|null $pos Start position of the new buffer
+ * @param int $length Length of the new buffer. Mustn't be negative
+ */
+ public function reset($pos = 0, $length = 200)
+ {
+ if ($pos === null) {
+ $pos = $this->position + $this->offset;
+ } elseif ($pos < 0) {
+ $pos = \max(0, $this->getTotalLength() + $pos);
+ }
+
+ \fseek($this->stream, $pos);
+
+ $this->position = $pos;
+ $this->buffer = $length > 0 ? \fread($this->stream, $length) : '';
+ $this->bufferLength = \strlen($this->buffer);
+ $this->offset = 0;
+
+ // If a stream wrapper is in use it is possible that
+ // length values > 8096 will be ignored, so use the
+ // increaseLength()-method to correct that behavior
+ if ($this->bufferLength < $length && $this->increaseLength($length - $this->bufferLength)) {
+ // increaseLength parameter is $minLength, so cut to have only the required bytes in the buffer
+ $this->buffer = \substr($this->buffer, 0, $length);
+ $this->bufferLength = \strlen($this->buffer);
+ }
+ }
+
+ /**
+ * Ensures bytes in the buffer with a specific length and location in the file.
+ *
+ * @param int $pos
+ * @param int $length
+ * @see reset()
+ */
+ public function ensure($pos, $length)
+ {
+ if (
+ $pos >= $this->position
+ && $pos < ($this->position + $this->bufferLength)
+ && ($this->position + $this->bufferLength) >= ($pos + $length)
+ ) {
+ $this->offset = $pos - $this->position;
+ } else {
+ $this->reset($pos, $length);
+ }
+ }
+
+ /**
+ * Forcefully read more data into the buffer.
+ *
+ * @param int $minLength
+ * @return bool Returns false if the stream reaches the end
+ */
+ public function increaseLength($minLength = 100)
+ {
+ $length = \max($minLength, 100);
+
+ if (\feof($this->stream) || $this->getTotalLength() === $this->position + $this->bufferLength) {
+ return false;
+ }
+
+ $newLength = $this->bufferLength + $length;
+ do {
+ $this->buffer .= \fread($this->stream, $newLength - $this->bufferLength);
+ $this->bufferLength = \strlen($this->buffer);
+ } while (($this->bufferLength !== $newLength) && !\feof($this->stream));
+
+ return true;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Tokenizer.php b/vendor/setasign/fpdi/src/PdfParser/Tokenizer.php
new file mode 100644
index 0000000..a3bcd01
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Tokenizer.php
@@ -0,0 +1,154 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser;
+
+/**
+ * A tokenizer class.
+ */
+class Tokenizer
+{
+ /**
+ * @var StreamReader
+ */
+ protected $streamReader;
+
+ /**
+ * A token stack.
+ *
+ * @var string[]
+ */
+ protected $stack = [];
+
+ /**
+ * Tokenizer constructor.
+ *
+ * @param StreamReader $streamReader
+ */
+ public function __construct(StreamReader $streamReader)
+ {
+ $this->streamReader = $streamReader;
+ }
+
+ /**
+ * Get the stream reader instance.
+ *
+ * @return StreamReader
+ */
+ public function getStreamReader()
+ {
+ return $this->streamReader;
+ }
+
+ /**
+ * Clear the token stack.
+ */
+ public function clearStack()
+ {
+ $this->stack = [];
+ }
+
+ /**
+ * Push a token onto the stack.
+ *
+ * @param string $token
+ */
+ public function pushStack($token)
+ {
+ $this->stack[] = $token;
+ }
+
+ /**
+ * Get next token.
+ *
+ * @return bool|string
+ */
+ public function getNextToken()
+ {
+ $token = \array_pop($this->stack);
+ if ($token !== null) {
+ return $token;
+ }
+
+ if (($byte = $this->streamReader->readByte()) === false) {
+ return false;
+ }
+
+ if (\in_array($byte, ["\x20", "\x0A", "\x0D", "\x0C", "\x09", "\x00"], true)) {
+ if ($this->leapWhiteSpaces() === false) {
+ return false;
+ }
+ $byte = $this->streamReader->readByte();
+ }
+
+ switch ($byte) {
+ case '/':
+ case '[':
+ case ']':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '<':
+ case '>':
+ return $byte;
+ case '%':
+ $this->streamReader->readLine();
+ return $this->getNextToken();
+ }
+
+ /* This way is faster than checking single bytes.
+ */
+ $bufferOffset = $this->streamReader->getOffset();
+ do {
+ $lastBuffer = $this->streamReader->getBuffer(false);
+ $pos = \strcspn(
+ $lastBuffer,
+ "\x00\x09\x0A\x0C\x0D\x20()<>[]{}/%",
+ $bufferOffset
+ );
+ } while (
+ // Break the loop if a delimiter or white space char is matched
+ // in the current buffer or increase the buffers length
+ $lastBuffer !== false &&
+ (
+ $bufferOffset + $pos === \strlen($lastBuffer) &&
+ $this->streamReader->increaseLength()
+ )
+ );
+
+ $result = \substr($lastBuffer, $bufferOffset - 1, $pos + 1);
+ $this->streamReader->setOffset($bufferOffset + $pos);
+
+ return $result;
+ }
+
+ /**
+ * Leap white spaces.
+ *
+ * @return boolean
+ */
+ public function leapWhiteSpaces()
+ {
+ do {
+ if (!$this->streamReader->ensureContent()) {
+ return false;
+ }
+
+ $buffer = $this->streamReader->getBuffer(false);
+ $matches = \strspn($buffer, "\x20\x0A\x0C\x0D\x09\x00", $this->streamReader->getOffset());
+ if ($matches > 0) {
+ $this->streamReader->addOffset($matches);
+ }
+ } while ($this->streamReader->getOffset() >= $this->streamReader->getBufferLength());
+
+ return true;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfArray.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfArray.php
new file mode 100644
index 0000000..5d0bbbd
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfArray.php
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\Tokenizer;
+
+/**
+ * Class representing a PDF array object
+ *
+ * @property array $value The value of the PDF type.
+ */
+class PdfArray extends PdfType
+{
+ /**
+ * Parses an array of the passed tokenizer and parser.
+ *
+ * @param Tokenizer $tokenizer
+ * @param PdfParser $parser
+ * @return bool|self
+ * @throws PdfTypeException
+ */
+ public static function parse(Tokenizer $tokenizer, PdfParser $parser)
+ {
+ $result = [];
+
+ // Recurse into this function until we reach the end of the array.
+ while (($token = $tokenizer->getNextToken()) !== ']') {
+ if ($token === false || ($value = $parser->readValue($token)) === false) {
+ return false;
+ }
+
+ $result[] = $value;
+ }
+
+ $v = new self();
+ $v->value = $result;
+
+ return $v;
+ }
+
+ /**
+ * Helper method to create an instance.
+ *
+ * @param PdfType[] $values
+ * @return self
+ */
+ public static function create(array $values = [])
+ {
+ $v = new self();
+ $v->value = $values;
+
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed array is a PdfArray instance with a (optional) specific size.
+ *
+ * @param mixed $array
+ * @param null|int $size
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($array, $size = null)
+ {
+ $result = PdfType::ensureType(self::class, $array, 'Array value expected.');
+
+ if ($size !== null && \count($array->value) !== $size) {
+ throw new PdfTypeException(
+ \sprintf('Array with %s entries expected.', $size),
+ PdfTypeException::INVALID_DATA_SIZE
+ );
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfBoolean.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfBoolean.php
new file mode 100644
index 0000000..ba4233a
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfBoolean.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+/**
+ * Class representing a boolean PDF object
+ */
+class PdfBoolean extends PdfType
+{
+ /**
+ * Helper method to create an instance.
+ *
+ * @param bool $value
+ * @return self
+ */
+ public static function create($value)
+ {
+ $v = new self();
+ $v->value = (bool) $value;
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfBoolean instance.
+ *
+ * @param mixed $value
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($value)
+ {
+ return PdfType::ensureType(self::class, $value, 'Boolean value expected.');
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfDictionary.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfDictionary.php
new file mode 100644
index 0000000..2818842
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfDictionary.php
@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\StreamReader;
+use setasign\Fpdi\PdfParser\Tokenizer;
+
+/**
+ * Class representing a PDF dictionary object
+ */
+class PdfDictionary extends PdfType
+{
+ /**
+ * Parses a dictionary of the passed tokenizer, stream-reader and parser.
+ *
+ * @param Tokenizer $tokenizer
+ * @param StreamReader $streamReader
+ * @param PdfParser $parser
+ * @return bool|self
+ * @throws PdfTypeException
+ */
+ public static function parse(Tokenizer $tokenizer, StreamReader $streamReader, PdfParser $parser)
+ {
+ $entries = [];
+
+ while (true) {
+ $token = $tokenizer->getNextToken();
+ if ($token === '>' && $streamReader->getByte() === '>') {
+ $streamReader->addOffset(1);
+ break;
+ }
+
+ $key = $parser->readValue($token);
+ if ($key === false) {
+ return false;
+ }
+
+ // ensure the first value to be a Name object
+ if (!($key instanceof PdfName)) {
+ $lastToken = null;
+ // ignore all other entries and search for the closing brackets
+ while (($token = $tokenizer->getNextToken()) !== '>' && $token !== false && $lastToken !== '>') {
+ $lastToken = $token;
+ }
+
+ if ($token === false) {
+ return false;
+ }
+
+ break;
+ }
+
+
+ $value = $parser->readValue();
+ if ($value === false) {
+ return false;
+ }
+
+ if ($value instanceof PdfNull) {
+ continue;
+ }
+
+ // catch missing value
+ if ($value instanceof PdfToken && $value->value === '>' && $streamReader->getByte() === '>') {
+ $streamReader->addOffset(1);
+ break;
+ }
+
+ $entries[$key->value] = $value;
+ }
+
+ $v = new self();
+ $v->value = $entries;
+
+ return $v;
+ }
+
+ /**
+ * Helper method to create an instance.
+ *
+ * @param PdfType[] $entries The keys are the name entries of the dictionary.
+ * @return self
+ */
+ public static function create(array $entries = [])
+ {
+ $v = new self();
+ $v->value = $entries;
+
+ return $v;
+ }
+
+ /**
+ * Get a value by its key from a dictionary or a default value.
+ *
+ * @param mixed $dictionary
+ * @param string $key
+ * @param PdfType|null $default
+ * @return PdfNull|PdfType
+ * @throws PdfTypeException
+ */
+ public static function get($dictionary, $key, PdfType $default = null)
+ {
+ $dictionary = self::ensure($dictionary);
+
+ if (isset($dictionary->value[$key])) {
+ return $dictionary->value[$key];
+ }
+
+ return $default === null
+ ? new PdfNull()
+ : $default;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfDictionary instance.
+ *
+ * @param mixed $dictionary
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($dictionary)
+ {
+ return PdfType::ensureType(self::class, $dictionary, 'Dictionary value expected.');
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfHexString.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfHexString.php
new file mode 100644
index 0000000..0084ada
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfHexString.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+use setasign\Fpdi\PdfParser\StreamReader;
+
+/**
+ * Class representing a hexadecimal encoded PDF string object
+ */
+class PdfHexString extends PdfType
+{
+ /**
+ * Parses a hexadecimal string object from the stream reader.
+ *
+ * @param StreamReader $streamReader
+ * @return bool|self
+ */
+ public static function parse(StreamReader $streamReader)
+ {
+ $bufferOffset = $streamReader->getOffset();
+
+ while (true) {
+ $buffer = $streamReader->getBuffer(false);
+ $pos = \strpos($buffer, '>', $bufferOffset);
+ if ($pos === false) {
+ if (!$streamReader->increaseLength()) {
+ return false;
+ }
+ continue;
+ }
+
+ break;
+ }
+
+ $result = \substr($buffer, $bufferOffset, $pos - $bufferOffset);
+ $streamReader->setOffset($pos + 1);
+
+ $v = new self();
+ $v->value = $result;
+
+ return $v;
+ }
+
+ /**
+ * Helper method to create an instance.
+ *
+ * @param string $string The hex encoded string.
+ * @return self
+ */
+ public static function create($string)
+ {
+ $v = new self();
+ $v->value = $string;
+
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfHexString instance.
+ *
+ * @param mixed $hexString
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($hexString)
+ {
+ return PdfType::ensureType(self::class, $hexString, 'Hex string value expected.');
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfIndirectObject.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfIndirectObject.php
new file mode 100644
index 0000000..15786d0
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfIndirectObject.php
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\StreamReader;
+use setasign\Fpdi\PdfParser\Tokenizer;
+
+/**
+ * Class representing an indirect object
+ */
+class PdfIndirectObject extends PdfType
+{
+ /**
+ * Parses an indirect object from a tokenizer, parser and stream-reader.
+ *
+ * @param int $objectNumberToken
+ * @param int $objectGenerationNumberToken
+ * @param PdfParser $parser
+ * @param Tokenizer $tokenizer
+ * @param StreamReader $reader
+ * @return bool|self
+ * @throws PdfTypeException
+ */
+ public static function parse(
+ $objectNumberToken,
+ $objectGenerationNumberToken,
+ PdfParser $parser,
+ Tokenizer $tokenizer,
+ StreamReader $reader
+ ) {
+ $value = $parser->readValue();
+ if ($value === false) {
+ return false;
+ }
+
+ $nextToken = $tokenizer->getNextToken();
+ if ($nextToken === 'stream') {
+ $value = PdfStream::parse($value, $reader, $parser);
+ } elseif ($nextToken !== false) {
+ $tokenizer->pushStack($nextToken);
+ }
+
+ $v = new self();
+ $v->objectNumber = (int) $objectNumberToken;
+ $v->generationNumber = (int) $objectGenerationNumberToken;
+ $v->value = $value;
+
+ return $v;
+ }
+
+ /**
+ * Helper method to create an instance.
+ *
+ * @param int $objectNumber
+ * @param int $generationNumber
+ * @param PdfType $value
+ * @return self
+ */
+ public static function create($objectNumber, $generationNumber, PdfType $value)
+ {
+ $v = new self();
+ $v->objectNumber = (int) $objectNumber;
+ $v->generationNumber = (int) $generationNumber;
+ $v->value = $value;
+
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfIndirectObject instance.
+ *
+ * @param mixed $indirectObject
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($indirectObject)
+ {
+ return PdfType::ensureType(self::class, $indirectObject, 'Indirect object expected.');
+ }
+
+ /**
+ * The object number.
+ *
+ * @var int
+ */
+ public $objectNumber;
+
+ /**
+ * The generation number.
+ *
+ * @var int
+ */
+ public $generationNumber;
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfIndirectObjectReference.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfIndirectObjectReference.php
new file mode 100644
index 0000000..2725d0c
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfIndirectObjectReference.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+/**
+ * Class representing an indirect object reference
+ */
+class PdfIndirectObjectReference extends PdfType
+{
+ /**
+ * Helper method to create an instance.
+ *
+ * @param int $objectNumber
+ * @param int $generationNumber
+ * @return self
+ */
+ public static function create($objectNumber, $generationNumber)
+ {
+ $v = new self();
+ $v->value = (int) $objectNumber;
+ $v->generationNumber = (int) $generationNumber;
+
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfIndirectObject instance.
+ *
+ * @param mixed $value
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($value)
+ {
+ return PdfType::ensureType(self::class, $value, 'Indirect reference value expected.');
+ }
+
+ /**
+ * The generation number.
+ *
+ * @var int
+ */
+ public $generationNumber;
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfName.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfName.php
new file mode 100644
index 0000000..194a13f
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfName.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+use setasign\Fpdi\PdfParser\StreamReader;
+use setasign\Fpdi\PdfParser\Tokenizer;
+
+/**
+ * Class representing a PDF name object
+ */
+class PdfName extends PdfType
+{
+ /**
+ * Parses a name object from the passed tokenizer and stream-reader.
+ *
+ * @param Tokenizer $tokenizer
+ * @param StreamReader $streamReader
+ * @return self
+ */
+ public static function parse(Tokenizer $tokenizer, StreamReader $streamReader)
+ {
+ $v = new self();
+ if (\strspn($streamReader->getByte(), "\x00\x09\x0A\x0C\x0D\x20()<>[]{}/%") === 0) {
+ $v->value = (string) $tokenizer->getNextToken();
+ return $v;
+ }
+
+ $v->value = '';
+ return $v;
+ }
+
+ /**
+ * Unescapes a name string.
+ *
+ * @param string $value
+ * @return string
+ */
+ public static function unescape($value)
+ {
+ if (strpos($value, '#') === false) {
+ return $value;
+ }
+
+ return preg_replace_callback('/#([a-fA-F\d]{2})/', function ($matches) {
+ return chr(hexdec($matches[1]));
+ }, $value);
+ }
+
+ /**
+ * Helper method to create an instance.
+ *
+ * @param string $string
+ * @return self
+ */
+ public static function create($string)
+ {
+ $v = new self();
+ $v->value = $string;
+
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfName instance.
+ *
+ * @param mixed $name
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($name)
+ {
+ return PdfType::ensureType(self::class, $name, 'Name value expected.');
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfNull.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfNull.php
new file mode 100644
index 0000000..0c4c108
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfNull.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+/**
+ * Class representing a PDF null object
+ */
+class PdfNull extends PdfType
+{
+ // empty body
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfNumeric.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfNumeric.php
new file mode 100644
index 0000000..9de912b
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfNumeric.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+/**
+ * Class representing a numeric PDF object
+ */
+class PdfNumeric extends PdfType
+{
+ /**
+ * Helper method to create an instance.
+ *
+ * @param int|float $value
+ * @return PdfNumeric
+ */
+ public static function create($value)
+ {
+ $v = new self();
+ $v->value = $value + 0;
+
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfNumeric instance.
+ *
+ * @param mixed $value
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($value)
+ {
+ return PdfType::ensureType(self::class, $value, 'Numeric value expected.');
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfStream.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfStream.php
new file mode 100644
index 0000000..6d4c5a8
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfStream.php
@@ -0,0 +1,326 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+use setasign\Fpdi\PdfParser\Filter\Ascii85;
+use setasign\Fpdi\PdfParser\Filter\AsciiHex;
+use setasign\Fpdi\PdfParser\Filter\FilterException;
+use setasign\Fpdi\PdfParser\Filter\Flate;
+use setasign\Fpdi\PdfParser\Filter\Lzw;
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\PdfParserException;
+use setasign\Fpdi\PdfParser\StreamReader;
+use setasign\FpdiPdfParser\PdfParser\Filter\Predictor;
+
+/**
+ * Class representing a PDF stream object
+ */
+class PdfStream extends PdfType
+{
+ /**
+ * Parses a stream from a stream reader.
+ *
+ * @param PdfDictionary $dictionary
+ * @param StreamReader $reader
+ * @param PdfParser $parser Optional to keep backwards compatibility
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function parse(PdfDictionary $dictionary, StreamReader $reader, PdfParser $parser = null)
+ {
+ $v = new self();
+ $v->value = $dictionary;
+ $v->reader = $reader;
+ $v->parser = $parser;
+
+ $offset = $reader->getOffset();
+
+ // Find the first "newline"
+ while (($firstByte = $reader->getByte($offset)) !== false) {
+ if ($firstByte !== "\n" && $firstByte !== "\r") {
+ $offset++;
+ } else {
+ break;
+ }
+ }
+
+ if ($firstByte === false) {
+ throw new PdfTypeException(
+ 'Unable to parse stream data. No newline after the stream keyword found.',
+ PdfTypeException::NO_NEWLINE_AFTER_STREAM_KEYWORD
+ );
+ }
+
+ $sndByte = $reader->getByte($offset + 1);
+ if ($firstByte === "\n" || $firstByte === "\r") {
+ $offset++;
+ }
+
+ if ($sndByte === "\n" && $firstByte !== "\n") {
+ $offset++;
+ }
+
+ $reader->setOffset($offset);
+ // let's only save the byte-offset and read the stream only when needed
+ $v->stream = $reader->getPosition() + $reader->getOffset();
+
+ return $v;
+ }
+
+ /**
+ * Helper method to create an instance.
+ *
+ * @param PdfDictionary $dictionary
+ * @param string $stream
+ * @return self
+ */
+ public static function create(PdfDictionary $dictionary, $stream)
+ {
+ $v = new self();
+ $v->value = $dictionary;
+ $v->stream = (string) $stream;
+
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfStream instance.
+ *
+ * @param mixed $stream
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($stream)
+ {
+ return PdfType::ensureType(self::class, $stream, 'Stream value expected.');
+ }
+
+ /**
+ * The stream or its byte-offset position.
+ *
+ * @var int|string
+ */
+ protected $stream;
+
+ /**
+ * The stream reader instance.
+ *
+ * @var StreamReader|null
+ */
+ protected $reader;
+
+ /**
+ * The PDF parser instance.
+ *
+ * @var PdfParser
+ */
+ protected $parser;
+
+ /**
+ * Get the stream data.
+ *
+ * @param bool $cache Whether cache the stream data or not.
+ * @return bool|string
+ * @throws PdfTypeException
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ public function getStream($cache = false)
+ {
+ if (\is_int($this->stream)) {
+ $length = PdfDictionary::get($this->value, 'Length');
+ if ($this->parser !== null) {
+ $length = PdfType::resolve($length, $this->parser);
+ }
+
+ if (!($length instanceof PdfNumeric) || $length->value === 0) {
+ $this->reader->reset($this->stream, 100000);
+ $buffer = $this->extractStream();
+ } else {
+ $this->reader->reset($this->stream, $length->value);
+ $buffer = $this->reader->getBuffer(false);
+ if ($this->parser !== null) {
+ $this->reader->reset($this->stream + strlen($buffer));
+ $this->parser->getTokenizer()->clearStack();
+ $token = $this->parser->readValue();
+ if ($token === false || !($token instanceof PdfToken) || $token->value !== 'endstream') {
+ $this->reader->reset($this->stream, 100000);
+ $buffer = $this->extractStream();
+ $this->reader->reset($this->stream + strlen($buffer));
+ }
+ }
+ }
+
+ if ($cache === false) {
+ return $buffer;
+ }
+
+ $this->stream = $buffer;
+ $this->reader = null;
+ }
+
+ return $this->stream;
+ }
+
+ /**
+ * Extract the stream "manually".
+ *
+ * @return string
+ * @throws PdfTypeException
+ */
+ protected function extractStream()
+ {
+ while (true) {
+ $buffer = $this->reader->getBuffer(false);
+ $length = \strpos($buffer, 'endstream');
+ if ($length === false) {
+ if (!$this->reader->increaseLength(100000)) {
+ throw new PdfTypeException('Cannot extract stream.');
+ }
+ continue;
+ }
+ break;
+ }
+
+ $buffer = \substr($buffer, 0, $length);
+ $lastByte = \substr($buffer, -1);
+
+ /* Check for EOL marker =
+ * CARRIAGE RETURN (\r) and a LINE FEED (\n) or just a LINE FEED (\n},
+ * and not by a CARRIAGE RETURN (\r) alone
+ */
+ if ($lastByte === "\n") {
+ $buffer = \substr($buffer, 0, -1);
+
+ $lastByte = \substr($buffer, -1);
+ if ($lastByte === "\r") {
+ $buffer = \substr($buffer, 0, -1);
+ }
+ }
+
+ // There are streams in the wild, which have only white signs in them but need to be parsed manually due
+ // to a problem encountered before (e.g. Length === 0). We should set them to empty streams to avoid problems
+ // in further processing (e.g. applying of filters).
+ if (trim($buffer) === '') {
+ $buffer = '';
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Get the unfiltered stream data.
+ *
+ * @return string
+ * @throws FilterException
+ * @throws PdfParserException
+ */
+ public function getUnfilteredStream()
+ {
+ $stream = $this->getStream();
+ $filters = PdfDictionary::get($this->value, 'Filter');
+ if ($filters instanceof PdfNull) {
+ return $stream;
+ }
+
+ if ($filters instanceof PdfArray) {
+ $filters = $filters->value;
+ } else {
+ $filters = [$filters];
+ }
+
+ $decodeParams = PdfDictionary::get($this->value, 'DecodeParms');
+ if ($decodeParams instanceof PdfArray) {
+ $decodeParams = $decodeParams->value;
+ } else {
+ $decodeParams = [$decodeParams];
+ }
+
+ foreach ($filters as $key => $filter) {
+ if (!($filter instanceof PdfName)) {
+ continue;
+ }
+
+ $decodeParam = null;
+ if (isset($decodeParams[$key])) {
+ $decodeParam = ($decodeParams[$key] instanceof PdfDictionary ? $decodeParams[$key] : null);
+ }
+
+ switch ($filter->value) {
+ case 'FlateDecode':
+ case 'Fl':
+ case 'LZWDecode':
+ case 'LZW':
+ if (\strpos($filter->value, 'LZW') === 0) {
+ $filterObject = new Lzw();
+ } else {
+ $filterObject = new Flate();
+ }
+
+ $stream = $filterObject->decode($stream);
+
+ if ($decodeParam instanceof PdfDictionary) {
+ $predictor = PdfDictionary::get($decodeParam, 'Predictor', PdfNumeric::create(1));
+ if ($predictor->value !== 1) {
+ if (!\class_exists(Predictor::class)) {
+ throw new PdfParserException(
+ 'This PDF document makes use of features which are only implemented in the ' .
+ 'commercial "FPDI PDF-Parser" add-on (see https://www.setasign.com/fpdi-pdf-' .
+ 'parser).',
+ PdfParserException::IMPLEMENTED_IN_FPDI_PDF_PARSER
+ );
+ }
+
+ $colors = PdfDictionary::get($decodeParam, 'Colors', PdfNumeric::create(1));
+ $bitsPerComponent = PdfDictionary::get(
+ $decodeParam,
+ 'BitsPerComponent',
+ PdfNumeric::create(8)
+ );
+
+ $columns = PdfDictionary::get($decodeParam, 'Columns', PdfNumeric::create(1));
+
+ $filterObject = new Predictor(
+ $predictor->value,
+ $colors->value,
+ $bitsPerComponent->value,
+ $columns->value
+ );
+
+ $stream = $filterObject->decode($stream);
+ }
+ }
+
+ break;
+ case 'ASCII85Decode':
+ case 'A85':
+ $filterObject = new Ascii85();
+ $stream = $filterObject->decode($stream);
+ break;
+
+ case 'ASCIIHexDecode':
+ case 'AHx':
+ $filterObject = new AsciiHex();
+ $stream = $filterObject->decode($stream);
+ break;
+
+ default:
+ throw new FilterException(
+ \sprintf('Unsupported filter "%s".', $filter->value),
+ FilterException::UNSUPPORTED_FILTER
+ );
+ }
+ }
+
+ return $stream;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfString.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfString.php
new file mode 100644
index 0000000..1636e68
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfString.php
@@ -0,0 +1,172 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+use setasign\Fpdi\PdfParser\StreamReader;
+
+/**
+ * Class representing a PDF string object
+ */
+class PdfString extends PdfType
+{
+ /**
+ * Parses a string object from the stream reader.
+ *
+ * @param StreamReader $streamReader
+ * @return self
+ */
+ public static function parse(StreamReader $streamReader)
+ {
+ $pos = $startPos = $streamReader->getOffset();
+ $openBrackets = 1;
+ do {
+ $buffer = $streamReader->getBuffer(false);
+ for ($length = \strlen($buffer); $openBrackets !== 0 && $pos < $length; $pos++) {
+ switch ($buffer[$pos]) {
+ case '(':
+ $openBrackets++;
+ break;
+ case ')':
+ $openBrackets--;
+ break;
+ case '\\':
+ $pos++;
+ }
+ }
+ } while ($openBrackets !== 0 && $streamReader->increaseLength());
+
+ $result = \substr($buffer, $startPos, $openBrackets + $pos - $startPos - 1);
+ $streamReader->setOffset($pos);
+
+ $v = new self();
+ $v->value = $result;
+
+ return $v;
+ }
+
+ /**
+ * Helper method to create an instance.
+ *
+ * @param string $value The string needs to be escaped accordingly.
+ * @return self
+ */
+ public static function create($value)
+ {
+ $v = new self();
+ $v->value = $value;
+
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfString instance.
+ *
+ * @param mixed $string
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($string)
+ {
+ return PdfType::ensureType(self::class, $string, 'String value expected.');
+ }
+
+ /**
+ * Unescapes escaped sequences in a PDF string according to the PDF specification.
+ *
+ * @param string $s
+ * @return string
+ */
+ public static function unescape($s)
+ {
+ $out = '';
+ /** @noinspection ForeachInvariantsInspection */
+ for ($count = 0, $n = \strlen($s); $count < $n; $count++) {
+ if ($s[$count] !== '\\') {
+ $out .= $s[$count];
+ } else {
+ // A backslash at the end of the string - ignore it
+ if ($count === ($n - 1)) {
+ break;
+ }
+
+ switch ($s[++$count]) {
+ case ')':
+ case '(':
+ case '\\':
+ $out .= $s[$count];
+ break;
+
+ case 'f':
+ $out .= "\x0C";
+ break;
+
+ case 'b':
+ $out .= "\x08";
+ break;
+
+ case 't':
+ $out .= "\x09";
+ break;
+
+ case 'r':
+ $out .= "\x0D";
+ break;
+
+ case 'n':
+ $out .= "\x0A";
+ break;
+
+ case "\r":
+ if ($count !== $n - 1 && $s[$count + 1] === "\n") {
+ $count++;
+ }
+ break;
+
+ case "\n":
+ break;
+
+ default:
+ $actualChar = \ord($s[$count]);
+ // ascii 48 = number 0
+ // ascii 57 = number 9
+ if ($actualChar >= 48 && $actualChar <= 57) {
+ $oct = '' . $s[$count];
+
+ /** @noinspection NotOptimalIfConditionsInspection */
+ if (
+ $count + 1 < $n
+ && \ord($s[$count + 1]) >= 48
+ && \ord($s[$count + 1]) <= 57
+ ) {
+ $count++;
+ $oct .= $s[$count];
+
+ /** @noinspection NotOptimalIfConditionsInspection */
+ if (
+ $count + 1 < $n
+ && \ord($s[$count + 1]) >= 48
+ && \ord($s[$count + 1]) <= 57
+ ) {
+ $oct .= $s[++$count];
+ }
+ }
+
+ $out .= \chr(\octdec($oct));
+ } else {
+ // If the character is not one of those defined, the backslash is ignored
+ $out .= $s[$count];
+ }
+ }
+ }
+ }
+ return $out;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfToken.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfToken.php
new file mode 100644
index 0000000..012b9fd
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfToken.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+/**
+ * Class representing PDF token object
+ */
+class PdfToken extends PdfType
+{
+ /**
+ * Helper method to create an instance.
+ *
+ * @param string $token
+ * @return self
+ */
+ public static function create($token)
+ {
+ $v = new self();
+ $v->value = $token;
+
+ return $v;
+ }
+
+ /**
+ * Ensures that the passed value is a PdfToken instance.
+ *
+ * @param mixed $token
+ * @return self
+ * @throws PdfTypeException
+ */
+ public static function ensure($token)
+ {
+ return PdfType::ensureType(self::class, $token, 'Token value expected.');
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfType.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfType.php
new file mode 100644
index 0000000..7672dcd
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfType.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\PdfParserException;
+
+/**
+ * A class defining a PDF data type
+ */
+class PdfType
+{
+ /**
+ * Resolves a PdfType value to its value.
+ *
+ * This method is used to evaluate indirect and direct object references until a final value is reached.
+ *
+ * @param PdfType $value
+ * @param PdfParser $parser
+ * @param bool $stopAtIndirectObject
+ * @return PdfType
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ public static function resolve(PdfType $value, PdfParser $parser, $stopAtIndirectObject = false)
+ {
+ if ($value instanceof PdfIndirectObject) {
+ if ($stopAtIndirectObject === true) {
+ return $value;
+ }
+
+ return self::resolve($value->value, $parser, $stopAtIndirectObject);
+ }
+
+ if ($value instanceof PdfIndirectObjectReference) {
+ return self::resolve($parser->getIndirectObject($value->value), $parser, $stopAtIndirectObject);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Ensure that a value is an instance of a specific PDF type.
+ *
+ * @param string $type
+ * @param PdfType $value
+ * @param string $errorMessage
+ * @return mixed
+ * @throws PdfTypeException
+ */
+ protected static function ensureType($type, $value, $errorMessage)
+ {
+ if (!($value instanceof $type)) {
+ throw new PdfTypeException(
+ $errorMessage,
+ PdfTypeException::INVALID_DATA_TYPE
+ );
+ }
+
+ return $value;
+ }
+
+ /**
+ * The value of the PDF type.
+ *
+ * @var mixed
+ */
+ public $value;
+}
diff --git a/vendor/setasign/fpdi/src/PdfParser/Type/PdfTypeException.php b/vendor/setasign/fpdi/src/PdfParser/Type/PdfTypeException.php
new file mode 100644
index 0000000..593d147
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfParser/Type/PdfTypeException.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfParser\Type;
+
+use setasign\Fpdi\PdfParser\PdfParserException;
+
+/**
+ * Exception class for pdf type classes
+ */
+class PdfTypeException extends PdfParserException
+{
+ /**
+ * @var int
+ */
+ const NO_NEWLINE_AFTER_STREAM_KEYWORD = 0x0601;
+}
diff --git a/vendor/setasign/fpdi/src/PdfReader/DataStructure/Rectangle.php b/vendor/setasign/fpdi/src/PdfReader/DataStructure/Rectangle.php
new file mode 100644
index 0000000..9b19ff8
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfReader/DataStructure/Rectangle.php
@@ -0,0 +1,173 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfReader\DataStructure;
+
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\PdfParserException;
+use setasign\Fpdi\PdfParser\Type\PdfArray;
+use setasign\Fpdi\PdfParser\Type\PdfNumeric;
+use setasign\Fpdi\PdfParser\Type\PdfType;
+use setasign\Fpdi\PdfParser\Type\PdfTypeException;
+
+/**
+ * Class representing a rectangle
+ */
+class Rectangle
+{
+ /**
+ * @var int|float
+ */
+ protected $llx;
+
+ /**
+ * @var int|float
+ */
+ protected $lly;
+
+ /**
+ * @var int|float
+ */
+ protected $urx;
+
+ /**
+ * @var int|float
+ */
+ protected $ury;
+
+ /**
+ * Create a rectangle instance by a PdfArray.
+ *
+ * @param PdfArray|mixed $array
+ * @param PdfParser $parser
+ * @return Rectangle
+ * @throws PdfTypeException
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ public static function byPdfArray($array, PdfParser $parser)
+ {
+ $array = PdfArray::ensure(PdfType::resolve($array, $parser), 4)->value;
+ $ax = PdfNumeric::ensure(PdfType::resolve($array[0], $parser))->value;
+ $ay = PdfNumeric::ensure(PdfType::resolve($array[1], $parser))->value;
+ $bx = PdfNumeric::ensure(PdfType::resolve($array[2], $parser))->value;
+ $by = PdfNumeric::ensure(PdfType::resolve($array[3], $parser))->value;
+
+ return new self($ax, $ay, $bx, $by);
+ }
+
+ /**
+ * Rectangle constructor.
+ *
+ * @param float|int $ax
+ * @param float|int $ay
+ * @param float|int $bx
+ * @param float|int $by
+ */
+ public function __construct($ax, $ay, $bx, $by)
+ {
+ $this->llx = \min($ax, $bx);
+ $this->lly = \min($ay, $by);
+ $this->urx = \max($ax, $bx);
+ $this->ury = \max($ay, $by);
+ }
+
+ /**
+ * Get the width of the rectangle.
+ *
+ * @return float|int
+ */
+ public function getWidth()
+ {
+ return $this->urx - $this->llx;
+ }
+
+ /**
+ * Get the height of the rectangle.
+ *
+ * @return float|int
+ */
+ public function getHeight()
+ {
+ return $this->ury - $this->lly;
+ }
+
+ /**
+ * Get the lower left abscissa.
+ *
+ * @return float|int
+ */
+ public function getLlx()
+ {
+ return $this->llx;
+ }
+
+ /**
+ * Get the lower left ordinate.
+ *
+ * @return float|int
+ */
+ public function getLly()
+ {
+ return $this->lly;
+ }
+
+ /**
+ * Get the upper right abscissa.
+ *
+ * @return float|int
+ */
+ public function getUrx()
+ {
+ return $this->urx;
+ }
+
+ /**
+ * Get the upper right ordinate.
+ *
+ * @return float|int
+ */
+ public function getUry()
+ {
+ return $this->ury;
+ }
+
+ /**
+ * Get the rectangle as an array.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return [
+ $this->llx,
+ $this->lly,
+ $this->urx,
+ $this->ury
+ ];
+ }
+
+ /**
+ * Get the rectangle as a PdfArray.
+ *
+ * @return PdfArray
+ */
+ public function toPdfArray()
+ {
+ $array = new PdfArray();
+ $array->value[] = PdfNumeric::create($this->llx);
+ $array->value[] = PdfNumeric::create($this->lly);
+ $array->value[] = PdfNumeric::create($this->urx);
+ $array->value[] = PdfNumeric::create($this->ury);
+
+ return $array;
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfReader/Page.php b/vendor/setasign/fpdi/src/PdfReader/Page.php
new file mode 100644
index 0000000..b207c79
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfReader/Page.php
@@ -0,0 +1,271 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfReader;
+
+use setasign\Fpdi\PdfParser\Filter\FilterException;
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\PdfParserException;
+use setasign\Fpdi\PdfParser\Type\PdfArray;
+use setasign\Fpdi\PdfParser\Type\PdfDictionary;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
+use setasign\Fpdi\PdfParser\Type\PdfNull;
+use setasign\Fpdi\PdfParser\Type\PdfNumeric;
+use setasign\Fpdi\PdfParser\Type\PdfStream;
+use setasign\Fpdi\PdfParser\Type\PdfType;
+use setasign\Fpdi\PdfParser\Type\PdfTypeException;
+use setasign\Fpdi\PdfReader\DataStructure\Rectangle;
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+
+/**
+ * Class representing a page of a PDF document
+ */
+class Page
+{
+ /**
+ * @var PdfIndirectObject
+ */
+ protected $pageObject;
+
+ /**
+ * @var PdfDictionary
+ */
+ protected $pageDictionary;
+
+ /**
+ * @var PdfParser
+ */
+ protected $parser;
+
+ /**
+ * Inherited attributes
+ *
+ * @var null|array
+ */
+ protected $inheritedAttributes;
+
+ /**
+ * Page constructor.
+ *
+ * @param PdfIndirectObject $page
+ * @param PdfParser $parser
+ */
+ public function __construct(PdfIndirectObject $page, PdfParser $parser)
+ {
+ $this->pageObject = $page;
+ $this->parser = $parser;
+ }
+
+ /**
+ * Get the indirect object of this page.
+ *
+ * @return PdfIndirectObject
+ */
+ public function getPageObject()
+ {
+ return $this->pageObject;
+ }
+
+ /**
+ * Get the dictionary of this page.
+ *
+ * @return PdfDictionary
+ * @throws PdfParserException
+ * @throws PdfTypeException
+ * @throws CrossReferenceException
+ */
+ public function getPageDictionary()
+ {
+ if (null === $this->pageDictionary) {
+ $this->pageDictionary = PdfDictionary::ensure(PdfType::resolve($this->getPageObject(), $this->parser));
+ }
+
+ return $this->pageDictionary;
+ }
+
+ /**
+ * Get a page attribute.
+ *
+ * @param string $name
+ * @param bool $inherited
+ * @return PdfType|null
+ * @throws PdfParserException
+ * @throws PdfTypeException
+ * @throws CrossReferenceException
+ */
+ public function getAttribute($name, $inherited = true)
+ {
+ $dict = $this->getPageDictionary();
+
+ if (isset($dict->value[$name])) {
+ return $dict->value[$name];
+ }
+
+ $inheritedKeys = ['Resources', 'MediaBox', 'CropBox', 'Rotate'];
+ if ($inherited && \in_array($name, $inheritedKeys, true)) {
+ if ($this->inheritedAttributes === null) {
+ $this->inheritedAttributes = [];
+ $inheritedKeys = \array_filter($inheritedKeys, function ($key) use ($dict) {
+ return !isset($dict->value[$key]);
+ });
+
+ if (\count($inheritedKeys) > 0) {
+ $parentDict = PdfType::resolve(PdfDictionary::get($dict, 'Parent'), $this->parser);
+ while ($parentDict instanceof PdfDictionary) {
+ foreach ($inheritedKeys as $index => $key) {
+ if (isset($parentDict->value[$key])) {
+ $this->inheritedAttributes[$key] = $parentDict->value[$key];
+ unset($inheritedKeys[$index]);
+ }
+ }
+
+ /** @noinspection NotOptimalIfConditionsInspection */
+ if (isset($parentDict->value['Parent']) && \count($inheritedKeys) > 0) {
+ $parentDict = PdfType::resolve(PdfDictionary::get($parentDict, 'Parent'), $this->parser);
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ if (isset($this->inheritedAttributes[$name])) {
+ return $this->inheritedAttributes[$name];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the rotation value.
+ *
+ * @return int
+ * @throws PdfParserException
+ * @throws PdfTypeException
+ * @throws CrossReferenceException
+ */
+ public function getRotation()
+ {
+ $rotation = $this->getAttribute('Rotate');
+ if (null === $rotation) {
+ return 0;
+ }
+
+ $rotation = PdfNumeric::ensure(PdfType::resolve($rotation, $this->parser))->value % 360;
+
+ if ($rotation < 0) {
+ $rotation += 360;
+ }
+
+ return $rotation;
+ }
+
+ /**
+ * Get a boundary of this page.
+ *
+ * @param string $box
+ * @param bool $fallback
+ * @return bool|Rectangle
+ * @throws PdfParserException
+ * @throws PdfTypeException
+ * @throws CrossReferenceException
+ * @see PageBoundaries
+ */
+ public function getBoundary($box = PageBoundaries::CROP_BOX, $fallback = true)
+ {
+ $value = $this->getAttribute($box);
+
+ if ($value !== null) {
+ return Rectangle::byPdfArray($value, $this->parser);
+ }
+
+ if ($fallback === false) {
+ return false;
+ }
+
+ switch ($box) {
+ case PageBoundaries::BLEED_BOX:
+ case PageBoundaries::TRIM_BOX:
+ case PageBoundaries::ART_BOX:
+ return $this->getBoundary(PageBoundaries::CROP_BOX, true);
+ case PageBoundaries::CROP_BOX:
+ return $this->getBoundary(PageBoundaries::MEDIA_BOX, true);
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the width and height of this page.
+ *
+ * @param string $box
+ * @param bool $fallback
+ * @return array|bool
+ * @throws PdfParserException
+ * @throws PdfTypeException
+ * @throws CrossReferenceException
+ */
+ public function getWidthAndHeight($box = PageBoundaries::CROP_BOX, $fallback = true)
+ {
+ $boundary = $this->getBoundary($box, $fallback);
+ if ($boundary === false) {
+ return false;
+ }
+
+ $rotation = $this->getRotation();
+ $interchange = ($rotation / 90) % 2;
+
+ return [
+ $interchange ? $boundary->getHeight() : $boundary->getWidth(),
+ $interchange ? $boundary->getWidth() : $boundary->getHeight()
+ ];
+ }
+
+ /**
+ * Get the raw content stream.
+ *
+ * @return string
+ * @throws PdfReaderException
+ * @throws PdfTypeException
+ * @throws FilterException
+ * @throws PdfParserException
+ */
+ public function getContentStream()
+ {
+ $dict = $this->getPageDictionary();
+ $contents = PdfType::resolve(PdfDictionary::get($dict, 'Contents'), $this->parser);
+ if ($contents instanceof PdfNull) {
+ return '';
+ }
+
+ if ($contents instanceof PdfArray) {
+ $result = [];
+ foreach ($contents->value as $content) {
+ $content = PdfType::resolve($content, $this->parser);
+ if (!($content instanceof PdfStream)) {
+ continue;
+ }
+ $result[] = $content->getUnfilteredStream();
+ }
+
+ return \implode("\n", $result);
+ }
+
+ if ($contents instanceof PdfStream) {
+ return $contents->getUnfilteredStream();
+ }
+
+ throw new PdfReaderException(
+ 'Array or stream expected.',
+ PdfReaderException::UNEXPECTED_DATA_TYPE
+ );
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfReader/PageBoundaries.php b/vendor/setasign/fpdi/src/PdfReader/PageBoundaries.php
new file mode 100644
index 0000000..9a6a1f3
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfReader/PageBoundaries.php
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfReader;
+
+/**
+ * An abstract class for page boundary constants and some helper methods
+ */
+abstract class PageBoundaries
+{
+ /**
+ * MediaBox
+ *
+ * The media box defines the boundaries of the physical medium on which the page is to be printed.
+ *
+ * @see PDF 32000-1:2008 - 14.11.2 Page Boundaries
+ * @var string
+ */
+ const MEDIA_BOX = 'MediaBox';
+
+ /**
+ * CropBox
+ *
+ * The crop box defines the region to which the contents of the page shall be clipped (cropped) when displayed or
+ * printed.
+ *
+ * @see PDF 32000-1:2008 - 14.11.2 Page Boundaries
+ * @var string
+ */
+ const CROP_BOX = 'CropBox';
+
+ /**
+ * BleedBox
+ *
+ * The bleed box defines the region to which the contents of the page shall be clipped when output in a
+ * production environment.
+ *
+ * @see PDF 32000-1:2008 - 14.11.2 Page Boundaries
+ * @var string
+ */
+ const BLEED_BOX = 'BleedBox';
+
+ /**
+ * TrimBox
+ *
+ * The trim box defines the intended dimensions of the finished page after trimming.
+ *
+ * @see PDF 32000-1:2008 - 14.11.2 Page Boundaries
+ * @var string
+ */
+ const TRIM_BOX = 'TrimBox';
+
+ /**
+ * ArtBox
+ *
+ * The art box defines the extent of the page’s meaningful content (including potential white space) as intended
+ * by the page’s creator.
+ *
+ * @see PDF 32000-1:2008 - 14.11.2 Page Boundaries
+ * @var string
+ */
+ const ART_BOX = 'ArtBox';
+
+ /**
+ * All page boundaries
+ *
+ * @var array
+ */
+ public static $all = array(
+ self::MEDIA_BOX,
+ self::CROP_BOX,
+ self::BLEED_BOX,
+ self::TRIM_BOX,
+ self::ART_BOX
+ );
+
+ /**
+ * Checks if a name is a valid page boundary name.
+ *
+ * @param string $name The boundary name
+ * @return boolean A boolean value whether the name is valid or not.
+ */
+ public static function isValidName($name)
+ {
+ return \in_array($name, self::$all, true);
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfReader/PdfReader.php b/vendor/setasign/fpdi/src/PdfReader/PdfReader.php
new file mode 100644
index 0000000..3ee8878
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfReader/PdfReader.php
@@ -0,0 +1,234 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfReader;
+
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+use setasign\Fpdi\PdfParser\PdfParser;
+use setasign\Fpdi\PdfParser\PdfParserException;
+use setasign\Fpdi\PdfParser\Type\PdfArray;
+use setasign\Fpdi\PdfParser\Type\PdfDictionary;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObjectReference;
+use setasign\Fpdi\PdfParser\Type\PdfNumeric;
+use setasign\Fpdi\PdfParser\Type\PdfType;
+use setasign\Fpdi\PdfParser\Type\PdfTypeException;
+
+/**
+ * A PDF reader class
+ */
+class PdfReader
+{
+ /**
+ * @var PdfParser
+ */
+ protected $parser;
+
+ /**
+ * @var int
+ */
+ protected $pageCount;
+
+ /**
+ * Indirect objects of resolved pages.
+ *
+ * @var PdfIndirectObjectReference[]|PdfIndirectObject[]
+ */
+ protected $pages = [];
+
+ /**
+ * PdfReader constructor.
+ *
+ * @param PdfParser $parser
+ */
+ public function __construct(PdfParser $parser)
+ {
+ $this->parser = $parser;
+ }
+
+ /**
+ * PdfReader destructor.
+ */
+ public function __destruct()
+ {
+ if ($this->parser !== null) {
+ $this->parser->cleanUp();
+ }
+ }
+
+ /**
+ * Get the pdf parser instance.
+ *
+ * @return PdfParser
+ */
+ public function getParser()
+ {
+ return $this->parser;
+ }
+
+ /**
+ * Get the PDF version.
+ *
+ * @return string
+ * @throws PdfParserException
+ */
+ public function getPdfVersion()
+ {
+ return \implode('.', $this->parser->getPdfVersion());
+ }
+
+ /**
+ * Get the page count.
+ *
+ * @return int
+ * @throws PdfTypeException
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ public function getPageCount()
+ {
+ if ($this->pageCount === null) {
+ $catalog = $this->parser->getCatalog();
+
+ $pages = PdfType::resolve(PdfDictionary::get($catalog, 'Pages'), $this->parser);
+ $count = PdfType::resolve(PdfDictionary::get($pages, 'Count'), $this->parser);
+
+ $this->pageCount = PdfNumeric::ensure($count)->value;
+ }
+
+ return $this->pageCount;
+ }
+
+ /**
+ * Get a page instance.
+ *
+ * @param int $pageNumber
+ * @return Page
+ * @throws PdfTypeException
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ * @throws \InvalidArgumentException
+ */
+ public function getPage($pageNumber)
+ {
+ if (!\is_numeric($pageNumber)) {
+ throw new \InvalidArgumentException(
+ 'Page number needs to be a number.'
+ );
+ }
+
+ if ($pageNumber < 1 || $pageNumber > $this->getPageCount()) {
+ throw new \InvalidArgumentException(
+ \sprintf(
+ 'Page number "%s" out of available page range (1 - %s)',
+ $pageNumber,
+ $this->getPageCount()
+ )
+ );
+ }
+
+ $this->readPages();
+
+ $page = $this->pages[$pageNumber - 1];
+
+ if ($page instanceof PdfIndirectObjectReference) {
+ $readPages = function ($kids) use (&$readPages) {
+ $kids = PdfArray::ensure($kids);
+
+ /** @noinspection LoopWhichDoesNotLoopInspection */
+ foreach ($kids->value as $reference) {
+ $reference = PdfIndirectObjectReference::ensure($reference);
+ $object = $this->parser->getIndirectObject($reference->value);
+ $type = PdfDictionary::get($object->value, 'Type');
+
+ if ($type->value === 'Pages') {
+ return $readPages(PdfDictionary::get($object->value, 'Kids'));
+ }
+
+ return $object;
+ }
+
+ throw new PdfReaderException(
+ 'Kids array cannot be empty.',
+ PdfReaderException::KIDS_EMPTY
+ );
+ };
+
+ $page = $this->parser->getIndirectObject($page->value);
+ $dict = PdfType::resolve($page, $this->parser);
+ $type = PdfDictionary::get($dict, 'Type');
+
+ if ($type->value === 'Pages') {
+ $kids = PdfType::resolve(PdfDictionary::get($dict, 'Kids'), $this->parser);
+ try {
+ $page = $this->pages[$pageNumber - 1] = $readPages($kids);
+ } catch (PdfReaderException $e) {
+ if ($e->getCode() !== PdfReaderException::KIDS_EMPTY) {
+ throw $e;
+ }
+
+ // let's reset the pages array and read all page objects
+ $this->pages = [];
+ $this->readPages(true);
+ // @phpstan-ignore-next-line
+ $page = $this->pages[$pageNumber - 1];
+ }
+ } else {
+ $this->pages[$pageNumber - 1] = $page;
+ }
+ }
+
+ return new Page($page, $this->parser);
+ }
+
+ /**
+ * Walk the page tree and resolve all indirect objects of all pages.
+ *
+ * @param bool $readAll
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ * @throws PdfTypeException
+ */
+ protected function readPages($readAll = false)
+ {
+ if (\count($this->pages) > 0) {
+ return;
+ }
+
+ $readPages = function ($kids, $count) use (&$readPages, $readAll) {
+ $kids = PdfArray::ensure($kids);
+ $isLeaf = ($count->value === \count($kids->value));
+
+ foreach ($kids->value as $reference) {
+ $reference = PdfIndirectObjectReference::ensure($reference);
+
+ if (!$readAll && $isLeaf) {
+ $this->pages[] = $reference;
+ continue;
+ }
+
+ $object = $this->parser->getIndirectObject($reference->value);
+ $type = PdfDictionary::get($object->value, 'Type');
+
+ if ($type->value === 'Pages') {
+ $readPages(PdfDictionary::get($object->value, 'Kids'), PdfDictionary::get($object->value, 'Count'));
+ } else {
+ $this->pages[] = $object;
+ }
+ }
+ };
+
+ $catalog = $this->parser->getCatalog();
+ $pages = PdfType::resolve(PdfDictionary::get($catalog, 'Pages'), $this->parser);
+ $count = PdfType::resolve(PdfDictionary::get($pages, 'Count'), $this->parser);
+ $kids = PdfType::resolve(PdfDictionary::get($pages, 'Kids'), $this->parser);
+ $readPages($kids, $count);
+ }
+}
diff --git a/vendor/setasign/fpdi/src/PdfReader/PdfReaderException.php b/vendor/setasign/fpdi/src/PdfReader/PdfReaderException.php
new file mode 100644
index 0000000..99f7d12
--- /dev/null
+++ b/vendor/setasign/fpdi/src/PdfReader/PdfReaderException.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\PdfReader;
+
+use setasign\Fpdi\FpdiException;
+
+/**
+ * Exception for the pdf reader class
+ */
+class PdfReaderException extends FpdiException
+{
+ /**
+ * @var int
+ */
+ const KIDS_EMPTY = 0x0101;
+
+ /**
+ * @var int
+ */
+ const UNEXPECTED_DATA_TYPE = 0x0102;
+
+ /**
+ * @var int
+ */
+ const MISSING_DATA = 0x0103;
+}
diff --git a/vendor/setasign/fpdi/src/Tcpdf/Fpdi.php b/vendor/setasign/fpdi/src/Tcpdf/Fpdi.php
new file mode 100644
index 0000000..159f97b
--- /dev/null
+++ b/vendor/setasign/fpdi/src/Tcpdf/Fpdi.php
@@ -0,0 +1,270 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\Tcpdf;
+
+use setasign\Fpdi\FpdiTrait;
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+use setasign\Fpdi\PdfParser\Filter\AsciiHex;
+use setasign\Fpdi\PdfParser\PdfParserException;
+use setasign\Fpdi\PdfParser\Type\PdfHexString;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
+use setasign\Fpdi\PdfParser\Type\PdfNull;
+use setasign\Fpdi\PdfParser\Type\PdfNumeric;
+use setasign\Fpdi\PdfParser\Type\PdfStream;
+use setasign\Fpdi\PdfParser\Type\PdfString;
+use setasign\Fpdi\PdfParser\Type\PdfType;
+use setasign\Fpdi\PdfParser\Type\PdfTypeException;
+
+/**
+ * Class Fpdi
+ *
+ * This class let you import pages of existing PDF documents into a reusable structure for TCPDF.
+ *
+ * @method _encrypt_data(int $n, string $s) string
+ */
+class Fpdi extends \TCPDF
+{
+ use FpdiTrait {
+ writePdfType as fpdiWritePdfType;
+ useImportedPage as fpdiUseImportedPage;
+ }
+
+ /**
+ * FPDI version
+ *
+ * @string
+ */
+ const VERSION = '2.3.6';
+
+ /**
+ * A counter for template ids.
+ *
+ * @var int
+ */
+ protected $templateId = 0;
+
+ /**
+ * The currently used object number.
+ *
+ * @var int|null
+ */
+ protected $currentObjectNumber;
+
+ protected function _enddoc()
+ {
+ parent::_enddoc();
+ $this->cleanUp();
+ }
+
+ /**
+ * Get the next template id.
+ *
+ * @return int
+ */
+ protected function getNextTemplateId()
+ {
+ return $this->templateId++;
+ }
+
+ /**
+ * Draws an imported page onto the page or another template.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $tpl The template id
+ * @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array
+ * with the keys "x", "y", "width", "height", "adjustPageSize".
+ * @param float|int $y The ordinate of upper-left corner.
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @param bool $adjustPageSize
+ * @return array The size
+ * @see FpdiTrait::getTemplateSize()
+ */
+ public function useTemplate($tpl, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false)
+ {
+ return $this->useImportedPage($tpl, $x, $y, $width, $height, $adjustPageSize);
+ }
+
+ /**
+ * Draws an imported page onto the page.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $pageId The page id
+ * @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array
+ * with the keys "x", "y", "width", "height", "adjustPageSize".
+ * @param float|int $y The ordinate of upper-left corner.
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @param bool $adjustPageSize
+ * @return array The size.
+ * @see Fpdi::getTemplateSize()
+ */
+ public function useImportedPage($pageId, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false)
+ {
+ $size = $this->fpdiUseImportedPage($pageId, $x, $y, $width, $height, $adjustPageSize);
+ if ($this->inxobj) {
+ $importedPage = $this->importedPages[$pageId];
+ $this->xobjects[$this->xobjid]['importedPages'][$importedPage['id']] = $pageId;
+ }
+
+ return $size;
+ }
+
+ /**
+ * Get the size of an imported page.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $tpl The template id
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @return array|bool An array with following keys: width, height, 0 (=width), 1 (=height), orientation (L or P)
+ */
+ public function getTemplateSize($tpl, $width = null, $height = null)
+ {
+ return $this->getImportedPageSize($tpl, $width, $height);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function _getxobjectdict()
+ {
+ $out = parent::_getxobjectdict();
+
+ foreach ($this->importedPages as $key => $pageData) {
+ $out .= '/' . $pageData['id'] . ' ' . $pageData['objectNumber'] . ' 0 R ';
+ }
+
+ return $out;
+ }
+
+ /**
+ * @inheritdoc
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ protected function _putxobjects()
+ {
+ foreach ($this->importedPages as $key => $pageData) {
+ $this->currentObjectNumber = $this->_newobj();
+ $this->importedPages[$key]['objectNumber'] = $this->currentObjectNumber;
+ $this->currentReaderId = $pageData['readerId'];
+ $this->writePdfType($pageData['stream']);
+ $this->_put('endobj');
+ }
+
+ foreach (\array_keys($this->readers) as $readerId) {
+ $parser = $this->getPdfReader($readerId)->getParser();
+ $this->currentReaderId = $readerId;
+
+ while (($objectNumber = \array_pop($this->objectsToCopy[$readerId])) !== null) {
+ try {
+ $object = $parser->getIndirectObject($objectNumber);
+ } catch (CrossReferenceException $e) {
+ if ($e->getCode() === CrossReferenceException::OBJECT_NOT_FOUND) {
+ $object = PdfIndirectObject::create($objectNumber, 0, new PdfNull());
+ } else {
+ throw $e;
+ }
+ }
+
+ $this->writePdfType($object);
+ }
+ }
+
+ // let's prepare resources for imported pages in templates
+ foreach ($this->xobjects as $xObjectId => $data) {
+ if (!isset($data['importedPages'])) {
+ continue;
+ }
+
+ foreach ($data['importedPages'] as $id => $pageKey) {
+ $page = $this->importedPages[$pageKey];
+ $this->xobjects[$xObjectId]['xobjects'][$id] = ['n' => $page['objectNumber']];
+ }
+ }
+
+
+ parent::_putxobjects();
+ $this->currentObjectNumber = null;
+ }
+
+ /**
+ * Append content to the buffer of TCPDF.
+ *
+ * @param string $s
+ * @param bool $newLine
+ */
+ protected function _put($s, $newLine = true)
+ {
+ if ($newLine) {
+ $this->setBuffer($s . "\n");
+ } else {
+ $this->setBuffer($s);
+ }
+ }
+
+ /**
+ * Begin a new object and return the object number.
+ *
+ * @param int|string $objid Object ID (leave empty to get a new ID).
+ * @return int object number
+ */
+ protected function _newobj($objid = '')
+ {
+ $this->_out($this->_getobj($objid));
+ return $this->n;
+ }
+
+ /**
+ * Writes a PdfType object to the resulting buffer.
+ *
+ * @param PdfType $value
+ * @throws PdfTypeException
+ */
+ protected function writePdfType(PdfType $value)
+ {
+ if (!$this->encrypted) {
+ $this->fpdiWritePdfType($value);
+ return;
+ }
+
+ if ($value instanceof PdfString) {
+ $string = PdfString::unescape($value->value);
+ $string = $this->_encrypt_data($this->currentObjectNumber, $string);
+ $value->value = \TCPDF_STATIC::_escape($string);
+ } elseif ($value instanceof PdfHexString) {
+ $filter = new AsciiHex();
+ $string = $filter->decode($value->value);
+ $string = $this->_encrypt_data($this->currentObjectNumber, $string);
+ $value->value = $filter->encode($string, true);
+ } elseif ($value instanceof PdfStream) {
+ $stream = $value->getStream();
+ $stream = $this->_encrypt_data($this->currentObjectNumber, $stream);
+ $dictionary = $value->value;
+ $dictionary->value['Length'] = PdfNumeric::create(\strlen($stream));
+ $value = PdfStream::create($dictionary, $stream);
+ } elseif ($value instanceof PdfIndirectObject) {
+ /**
+ * @var PdfIndirectObject $value
+ */
+ $this->currentObjectNumber = $this->objectMap[$this->currentReaderId][$value->objectNumber];
+ }
+
+ $this->fpdiWritePdfType($value);
+ }
+}
diff --git a/vendor/setasign/fpdi/src/TcpdfFpdi.php b/vendor/setasign/fpdi/src/TcpdfFpdi.php
new file mode 100644
index 0000000..9e6825b
--- /dev/null
+++ b/vendor/setasign/fpdi/src/TcpdfFpdi.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi;
+
+/**
+ * Class TcpdfFpdi
+ *
+ * This class let you import pages of existing PDF documents into a reusable structure for TCPDF.
+ *
+ * @deprecated Class was moved to \setasign\Fpdi\Tcpdf\Fpdi
+ */
+class TcpdfFpdi extends \setasign\Fpdi\Tcpdf\Fpdi
+{
+ // this class is moved to \setasign\Fpdi\Tcpdf\Fpdi
+}
diff --git a/vendor/setasign/fpdi/src/Tfpdf/FpdfTpl.php b/vendor/setasign/fpdi/src/Tfpdf/FpdfTpl.php
new file mode 100644
index 0000000..c00d53d
--- /dev/null
+++ b/vendor/setasign/fpdi/src/Tfpdf/FpdfTpl.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\Tfpdf;
+
+use setasign\Fpdi\FpdfTplTrait;
+
+/**
+ * Class FpdfTpl
+ *
+ * We need to change some access levels and implement the setPageFormat() method to bring back compatibility to tFPDF.
+ */
+class FpdfTpl extends \tFPDF
+{
+ use FpdfTplTrait;
+}
diff --git a/vendor/setasign/fpdi/src/Tfpdf/Fpdi.php b/vendor/setasign/fpdi/src/Tfpdf/Fpdi.php
new file mode 100644
index 0000000..77f340f
--- /dev/null
+++ b/vendor/setasign/fpdi/src/Tfpdf/Fpdi.php
@@ -0,0 +1,154 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+namespace setasign\Fpdi\Tfpdf;
+
+use setasign\Fpdi\FpdiTrait;
+use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
+use setasign\Fpdi\PdfParser\PdfParserException;
+use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
+use setasign\Fpdi\PdfParser\Type\PdfNull;
+
+/**
+ * Class Fpdi
+ *
+ * This class let you import pages of existing PDF documents into a reusable structure for tFPDF.
+ */
+class Fpdi extends FpdfTpl
+{
+ use FpdiTrait;
+
+ /**
+ * FPDI version
+ *
+ * @string
+ */
+ const VERSION = '2.3.6';
+
+ public function _enddoc()
+ {
+ parent::_enddoc();
+ $this->cleanUp();
+ }
+
+ /**
+ * Draws an imported page or a template onto the page or another template.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $tpl The template id
+ * @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array
+ * with the keys "x", "y", "width", "height", "adjustPageSize".
+ * @param float|int $y The ordinate of upper-left corner.
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @param bool $adjustPageSize
+ * @return array The size
+ * @see Fpdi::getTemplateSize()
+ */
+ public function useTemplate($tpl, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false)
+ {
+ if (isset($this->importedPages[$tpl])) {
+ $size = $this->useImportedPage($tpl, $x, $y, $width, $height, $adjustPageSize);
+ if ($this->currentTemplateId !== null) {
+ $this->templates[$this->currentTemplateId]['resources']['templates']['importedPages'][$tpl] = $tpl;
+ }
+ return $size;
+ }
+
+ return parent::useTemplate($tpl, $x, $y, $width, $height, $adjustPageSize);
+ }
+
+ /**
+ * Get the size of an imported page or template.
+ *
+ * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the
+ * aspect ratio.
+ *
+ * @param mixed $tpl The template id
+ * @param float|int|null $width The width.
+ * @param float|int|null $height The height.
+ * @return array|bool An array with following keys: width, height, 0 (=width), 1 (=height), orientation (L or P)
+ */
+ public function getTemplateSize($tpl, $width = null, $height = null)
+ {
+ $size = parent::getTemplateSize($tpl, $width, $height);
+ if ($size === false) {
+ return $this->getImportedPageSize($tpl, $width, $height);
+ }
+
+ return $size;
+ }
+
+ /**
+ * @inheritdoc
+ * @throws CrossReferenceException
+ * @throws PdfParserException
+ */
+ public function _putimages()
+ {
+ $this->currentReaderId = null;
+ parent::_putimages();
+
+ foreach ($this->importedPages as $key => $pageData) {
+ $this->_newobj();
+ $this->importedPages[$key]['objectNumber'] = $this->n;
+ $this->currentReaderId = $pageData['readerId'];
+ $this->writePdfType($pageData['stream']);
+ $this->_put('endobj');
+ }
+
+ foreach (\array_keys($this->readers) as $readerId) {
+ $parser = $this->getPdfReader($readerId)->getParser();
+ $this->currentReaderId = $readerId;
+
+ while (($objectNumber = \array_pop($this->objectsToCopy[$readerId])) !== null) {
+ try {
+ $object = $parser->getIndirectObject($objectNumber);
+ } catch (CrossReferenceException $e) {
+ if ($e->getCode() === CrossReferenceException::OBJECT_NOT_FOUND) {
+ $object = PdfIndirectObject::create($objectNumber, 0, new PdfNull());
+ } else {
+ throw $e;
+ }
+ }
+
+ $this->writePdfType($object);
+ }
+ }
+
+ $this->currentReaderId = null;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function _putxobjectdict()
+ {
+ foreach ($this->importedPages as $key => $pageData) {
+ $this->_put('/' . $pageData['id'] . ' ' . $pageData['objectNumber'] . ' 0 R');
+ }
+
+ parent::_putxobjectdict();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function _put($s, $newLine = true)
+ {
+ if ($newLine) {
+ $this->buffer .= $s . "\n";
+ } else {
+ $this->buffer .= $s;
+ }
+ }
+}
diff --git a/vendor/setasign/fpdi/src/autoload.php b/vendor/setasign/fpdi/src/autoload.php
new file mode 100644
index 0000000..4c3df9d
--- /dev/null
+++ b/vendor/setasign/fpdi/src/autoload.php
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * This file is part of FPDI
+ *
+ * @package setasign\Fpdi
+ * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
+ * @license http://opensource.org/licenses/mit-license The MIT License
+ */
+
+spl_autoload_register(static function ($class) {
+ if (strpos($class, 'setasign\Fpdi\\') === 0) {
+ $filename = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 14)) . '.php';
+ $fullpath = __DIR__ . DIRECTORY_SEPARATOR . $filename;
+
+ if (is_file($fullpath)) {
+ /** @noinspection PhpIncludeInspection */
+ require_once $fullpath;
+ }
+ }
+});