1*dc4d9dc6SAnna Dabrowska<?php 2*dc4d9dc6SAnna Dabrowska 3*dc4d9dc6SAnna Dabrowskanamespace setasign\Fpdi\Tcpdf; 4*dc4d9dc6SAnna Dabrowska 5*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\FpdiTrait; 6*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException; 7*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Filter\AsciiHex; 8*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\PdfParserException; 9*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfHexString; 10*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfIndirectObject; 11*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfNull; 12*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfNumeric; 13*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfStream; 14*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfString; 15*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfType; 16*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfTypeException; 17*dc4d9dc6SAnna Dabrowska 18*dc4d9dc6SAnna Dabrowska/** 19*dc4d9dc6SAnna Dabrowska * Class Fpdi 20*dc4d9dc6SAnna Dabrowska * 21*dc4d9dc6SAnna Dabrowska * This class let you import pages of existing PDF documents into a reusable structure for TCPDF. 22*dc4d9dc6SAnna Dabrowska * 23*dc4d9dc6SAnna Dabrowska * @package setasign\Fpdi 24*dc4d9dc6SAnna Dabrowska */ 25*dc4d9dc6SAnna Dabrowskaclass Fpdi extends \TCPDF 26*dc4d9dc6SAnna Dabrowska{ 27*dc4d9dc6SAnna Dabrowska use FpdiTrait { 28*dc4d9dc6SAnna Dabrowska writePdfType as fpdiWritePdfType; 29*dc4d9dc6SAnna Dabrowska useImportedPage as fpdiUseImportedPage; 30*dc4d9dc6SAnna Dabrowska } 31*dc4d9dc6SAnna Dabrowska 32*dc4d9dc6SAnna Dabrowska /** 33*dc4d9dc6SAnna Dabrowska * FPDI version 34*dc4d9dc6SAnna Dabrowska * 35*dc4d9dc6SAnna Dabrowska * @string 36*dc4d9dc6SAnna Dabrowska */ 37*dc4d9dc6SAnna Dabrowska const VERSION = '2.3.1'; 38*dc4d9dc6SAnna Dabrowska 39*dc4d9dc6SAnna Dabrowska /** 40*dc4d9dc6SAnna Dabrowska * A counter for template ids. 41*dc4d9dc6SAnna Dabrowska * 42*dc4d9dc6SAnna Dabrowska * @var int 43*dc4d9dc6SAnna Dabrowska */ 44*dc4d9dc6SAnna Dabrowska protected $templateId = 0; 45*dc4d9dc6SAnna Dabrowska 46*dc4d9dc6SAnna Dabrowska /** 47*dc4d9dc6SAnna Dabrowska * The currently used object number. 48*dc4d9dc6SAnna Dabrowska * 49*dc4d9dc6SAnna Dabrowska * @var int 50*dc4d9dc6SAnna Dabrowska */ 51*dc4d9dc6SAnna Dabrowska protected $currentObjectNumber; 52*dc4d9dc6SAnna Dabrowska 53*dc4d9dc6SAnna Dabrowska protected function _enddoc() 54*dc4d9dc6SAnna Dabrowska { 55*dc4d9dc6SAnna Dabrowska parent::_enddoc(); 56*dc4d9dc6SAnna Dabrowska $this->cleanUp(); 57*dc4d9dc6SAnna Dabrowska } 58*dc4d9dc6SAnna Dabrowska 59*dc4d9dc6SAnna Dabrowska /** 60*dc4d9dc6SAnna Dabrowska * Get the next template id. 61*dc4d9dc6SAnna Dabrowska * 62*dc4d9dc6SAnna Dabrowska * @return int 63*dc4d9dc6SAnna Dabrowska */ 64*dc4d9dc6SAnna Dabrowska protected function getNextTemplateId() 65*dc4d9dc6SAnna Dabrowska { 66*dc4d9dc6SAnna Dabrowska return $this->templateId++; 67*dc4d9dc6SAnna Dabrowska } 68*dc4d9dc6SAnna Dabrowska 69*dc4d9dc6SAnna Dabrowska /** 70*dc4d9dc6SAnna Dabrowska * Draws an imported page onto the page or another template. 71*dc4d9dc6SAnna Dabrowska * 72*dc4d9dc6SAnna Dabrowska * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the 73*dc4d9dc6SAnna Dabrowska * aspect ratio. 74*dc4d9dc6SAnna Dabrowska * 75*dc4d9dc6SAnna Dabrowska * @param mixed $tpl The template id 76*dc4d9dc6SAnna Dabrowska * @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array 77*dc4d9dc6SAnna Dabrowska * with the keys "x", "y", "width", "height", "adjustPageSize". 78*dc4d9dc6SAnna Dabrowska * @param float|int $y The ordinate of upper-left corner. 79*dc4d9dc6SAnna Dabrowska * @param float|int|null $width The width. 80*dc4d9dc6SAnna Dabrowska * @param float|int|null $height The height. 81*dc4d9dc6SAnna Dabrowska * @param bool $adjustPageSize 82*dc4d9dc6SAnna Dabrowska * @return array The size 83*dc4d9dc6SAnna Dabrowska * @see FpdiTrait::getTemplateSize() 84*dc4d9dc6SAnna Dabrowska */ 85*dc4d9dc6SAnna Dabrowska public function useTemplate($tpl, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false) 86*dc4d9dc6SAnna Dabrowska { 87*dc4d9dc6SAnna Dabrowska return $this->useImportedPage($tpl, $x, $y, $width, $height, $adjustPageSize); 88*dc4d9dc6SAnna Dabrowska } 89*dc4d9dc6SAnna Dabrowska 90*dc4d9dc6SAnna Dabrowska /** 91*dc4d9dc6SAnna Dabrowska * Draws an imported page onto the page. 92*dc4d9dc6SAnna Dabrowska * 93*dc4d9dc6SAnna Dabrowska * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the 94*dc4d9dc6SAnna Dabrowska * aspect ratio. 95*dc4d9dc6SAnna Dabrowska * 96*dc4d9dc6SAnna Dabrowska * @param mixed $pageId The page id 97*dc4d9dc6SAnna Dabrowska * @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array 98*dc4d9dc6SAnna Dabrowska * with the keys "x", "y", "width", "height", "adjustPageSize". 99*dc4d9dc6SAnna Dabrowska * @param float|int $y The ordinate of upper-left corner. 100*dc4d9dc6SAnna Dabrowska * @param float|int|null $width The width. 101*dc4d9dc6SAnna Dabrowska * @param float|int|null $height The height. 102*dc4d9dc6SAnna Dabrowska * @param bool $adjustPageSize 103*dc4d9dc6SAnna Dabrowska * @return array The size. 104*dc4d9dc6SAnna Dabrowska * @see Fpdi::getTemplateSize() 105*dc4d9dc6SAnna Dabrowska */ 106*dc4d9dc6SAnna Dabrowska public function useImportedPage($pageId, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false) 107*dc4d9dc6SAnna Dabrowska { 108*dc4d9dc6SAnna Dabrowska $size = $this->fpdiUseImportedPage($pageId, $x, $y, $width, $height, $adjustPageSize); 109*dc4d9dc6SAnna Dabrowska if ($this->inxobj) { 110*dc4d9dc6SAnna Dabrowska $importedPage = $this->importedPages[$pageId]; 111*dc4d9dc6SAnna Dabrowska $this->xobjects[$this->xobjid]['importedPages'][$importedPage['id']] = $pageId; 112*dc4d9dc6SAnna Dabrowska } 113*dc4d9dc6SAnna Dabrowska 114*dc4d9dc6SAnna Dabrowska return $size; 115*dc4d9dc6SAnna Dabrowska } 116*dc4d9dc6SAnna Dabrowska 117*dc4d9dc6SAnna Dabrowska /** 118*dc4d9dc6SAnna Dabrowska * Get the size of an imported page. 119*dc4d9dc6SAnna Dabrowska * 120*dc4d9dc6SAnna Dabrowska * Give only one of the size parameters (width, height) to calculate the other one automatically in view to the 121*dc4d9dc6SAnna Dabrowska * aspect ratio. 122*dc4d9dc6SAnna Dabrowska * 123*dc4d9dc6SAnna Dabrowska * @param mixed $tpl The template id 124*dc4d9dc6SAnna Dabrowska * @param float|int|null $width The width. 125*dc4d9dc6SAnna Dabrowska * @param float|int|null $height The height. 126*dc4d9dc6SAnna Dabrowska * @return array|bool An array with following keys: width, height, 0 (=width), 1 (=height), orientation (L or P) 127*dc4d9dc6SAnna Dabrowska */ 128*dc4d9dc6SAnna Dabrowska public function getTemplateSize($tpl, $width = null, $height = null) 129*dc4d9dc6SAnna Dabrowska { 130*dc4d9dc6SAnna Dabrowska return $this->getImportedPageSize($tpl, $width, $height); 131*dc4d9dc6SAnna Dabrowska } 132*dc4d9dc6SAnna Dabrowska 133*dc4d9dc6SAnna Dabrowska /** 134*dc4d9dc6SAnna Dabrowska * @inheritdoc 135*dc4d9dc6SAnna Dabrowska */ 136*dc4d9dc6SAnna Dabrowska protected function _getxobjectdict() 137*dc4d9dc6SAnna Dabrowska { 138*dc4d9dc6SAnna Dabrowska $out = parent::_getxobjectdict(); 139*dc4d9dc6SAnna Dabrowska 140*dc4d9dc6SAnna Dabrowska foreach ($this->importedPages as $key => $pageData) { 141*dc4d9dc6SAnna Dabrowska $out .= '/' . $pageData['id'] . ' ' . $pageData['objectNumber'] . ' 0 R '; 142*dc4d9dc6SAnna Dabrowska } 143*dc4d9dc6SAnna Dabrowska 144*dc4d9dc6SAnna Dabrowska return $out; 145*dc4d9dc6SAnna Dabrowska } 146*dc4d9dc6SAnna Dabrowska 147*dc4d9dc6SAnna Dabrowska /** 148*dc4d9dc6SAnna Dabrowska * @inheritdoc 149*dc4d9dc6SAnna Dabrowska * @throws CrossReferenceException 150*dc4d9dc6SAnna Dabrowska * @throws PdfParserException 151*dc4d9dc6SAnna Dabrowska */ 152*dc4d9dc6SAnna Dabrowska protected function _putxobjects() 153*dc4d9dc6SAnna Dabrowska { 154*dc4d9dc6SAnna Dabrowska foreach ($this->importedPages as $key => $pageData) { 155*dc4d9dc6SAnna Dabrowska $this->currentObjectNumber = $this->_newobj(); 156*dc4d9dc6SAnna Dabrowska $this->importedPages[$key]['objectNumber'] = $this->currentObjectNumber; 157*dc4d9dc6SAnna Dabrowska $this->currentReaderId = $pageData['readerId']; 158*dc4d9dc6SAnna Dabrowska $this->writePdfType($pageData['stream']); 159*dc4d9dc6SAnna Dabrowska $this->_put('endobj'); 160*dc4d9dc6SAnna Dabrowska } 161*dc4d9dc6SAnna Dabrowska 162*dc4d9dc6SAnna Dabrowska foreach (\array_keys($this->readers) as $readerId) { 163*dc4d9dc6SAnna Dabrowska $parser = $this->getPdfReader($readerId)->getParser(); 164*dc4d9dc6SAnna Dabrowska $this->currentReaderId = $readerId; 165*dc4d9dc6SAnna Dabrowska 166*dc4d9dc6SAnna Dabrowska while (($objectNumber = \array_pop($this->objectsToCopy[$readerId])) !== null) { 167*dc4d9dc6SAnna Dabrowska try { 168*dc4d9dc6SAnna Dabrowska $object = $parser->getIndirectObject($objectNumber); 169*dc4d9dc6SAnna Dabrowska 170*dc4d9dc6SAnna Dabrowska } catch (CrossReferenceException $e) { 171*dc4d9dc6SAnna Dabrowska if ($e->getCode() === CrossReferenceException::OBJECT_NOT_FOUND) { 172*dc4d9dc6SAnna Dabrowska $object = PdfIndirectObject::create($objectNumber, 0, new PdfNull()); 173*dc4d9dc6SAnna Dabrowska } else { 174*dc4d9dc6SAnna Dabrowska throw $e; 175*dc4d9dc6SAnna Dabrowska } 176*dc4d9dc6SAnna Dabrowska } 177*dc4d9dc6SAnna Dabrowska 178*dc4d9dc6SAnna Dabrowska $this->writePdfType($object); 179*dc4d9dc6SAnna Dabrowska } 180*dc4d9dc6SAnna Dabrowska } 181*dc4d9dc6SAnna Dabrowska 182*dc4d9dc6SAnna Dabrowska // let's prepare resources for imported pages in templates 183*dc4d9dc6SAnna Dabrowska foreach ($this->xobjects as $xObjectId => $data) { 184*dc4d9dc6SAnna Dabrowska if (!isset($data['importedPages'])) { 185*dc4d9dc6SAnna Dabrowska continue; 186*dc4d9dc6SAnna Dabrowska } 187*dc4d9dc6SAnna Dabrowska 188*dc4d9dc6SAnna Dabrowska foreach ($data['importedPages'] as $id => $pageKey) { 189*dc4d9dc6SAnna Dabrowska $page = $this->importedPages[$pageKey]; 190*dc4d9dc6SAnna Dabrowska $this->xobjects[$xObjectId]['xobjects'][$id] = ['n' => $page['objectNumber']]; 191*dc4d9dc6SAnna Dabrowska } 192*dc4d9dc6SAnna Dabrowska } 193*dc4d9dc6SAnna Dabrowska 194*dc4d9dc6SAnna Dabrowska 195*dc4d9dc6SAnna Dabrowska parent::_putxobjects(); 196*dc4d9dc6SAnna Dabrowska $this->currentObjectNumber = null; 197*dc4d9dc6SAnna Dabrowska } 198*dc4d9dc6SAnna Dabrowska 199*dc4d9dc6SAnna Dabrowska /** 200*dc4d9dc6SAnna Dabrowska * Append content to the buffer of TCPDF. 201*dc4d9dc6SAnna Dabrowska * 202*dc4d9dc6SAnna Dabrowska * @param string $s 203*dc4d9dc6SAnna Dabrowska * @param bool $newLine 204*dc4d9dc6SAnna Dabrowska */ 205*dc4d9dc6SAnna Dabrowska protected function _put($s, $newLine = true) 206*dc4d9dc6SAnna Dabrowska { 207*dc4d9dc6SAnna Dabrowska if ($newLine) { 208*dc4d9dc6SAnna Dabrowska $this->setBuffer($s . "\n"); 209*dc4d9dc6SAnna Dabrowska } else { 210*dc4d9dc6SAnna Dabrowska $this->setBuffer($s); 211*dc4d9dc6SAnna Dabrowska } 212*dc4d9dc6SAnna Dabrowska } 213*dc4d9dc6SAnna Dabrowska 214*dc4d9dc6SAnna Dabrowska /** 215*dc4d9dc6SAnna Dabrowska * Begin a new object and return the object number. 216*dc4d9dc6SAnna Dabrowska * 217*dc4d9dc6SAnna Dabrowska * @param int|string $objid Object ID (leave empty to get a new ID). 218*dc4d9dc6SAnna Dabrowska * @return int object number 219*dc4d9dc6SAnna Dabrowska */ 220*dc4d9dc6SAnna Dabrowska protected function _newobj($objid = '') 221*dc4d9dc6SAnna Dabrowska { 222*dc4d9dc6SAnna Dabrowska $this->_out($this->_getobj($objid)); 223*dc4d9dc6SAnna Dabrowska return $this->n; 224*dc4d9dc6SAnna Dabrowska } 225*dc4d9dc6SAnna Dabrowska 226*dc4d9dc6SAnna Dabrowska /** 227*dc4d9dc6SAnna Dabrowska * Writes a PdfType object to the resulting buffer. 228*dc4d9dc6SAnna Dabrowska * 229*dc4d9dc6SAnna Dabrowska * @param PdfType $value 230*dc4d9dc6SAnna Dabrowska * @throws PdfTypeException 231*dc4d9dc6SAnna Dabrowska */ 232*dc4d9dc6SAnna Dabrowska protected function writePdfType(PdfType $value) 233*dc4d9dc6SAnna Dabrowska { 234*dc4d9dc6SAnna Dabrowska if (!$this->encrypted) { 235*dc4d9dc6SAnna Dabrowska $this->fpdiWritePdfType($value); 236*dc4d9dc6SAnna Dabrowska return; 237*dc4d9dc6SAnna Dabrowska } 238*dc4d9dc6SAnna Dabrowska 239*dc4d9dc6SAnna Dabrowska if ($value instanceof PdfString) { 240*dc4d9dc6SAnna Dabrowska $string = PdfString::unescape($value->value); 241*dc4d9dc6SAnna Dabrowska $string = $this->_encrypt_data($this->currentObjectNumber, $string); 242*dc4d9dc6SAnna Dabrowska $value->value = \TCPDF_STATIC::_escape($string); 243*dc4d9dc6SAnna Dabrowska 244*dc4d9dc6SAnna Dabrowska } elseif ($value instanceof PdfHexString) { 245*dc4d9dc6SAnna Dabrowska $filter = new AsciiHex(); 246*dc4d9dc6SAnna Dabrowska $string = $filter->decode($value->value); 247*dc4d9dc6SAnna Dabrowska $string = $this->_encrypt_data($this->currentObjectNumber, $string); 248*dc4d9dc6SAnna Dabrowska $value->value = $filter->encode($string, true); 249*dc4d9dc6SAnna Dabrowska 250*dc4d9dc6SAnna Dabrowska } elseif ($value instanceof PdfStream) { 251*dc4d9dc6SAnna Dabrowska $stream = $value->getStream(); 252*dc4d9dc6SAnna Dabrowska $stream = $this->_encrypt_data($this->currentObjectNumber, $stream); 253*dc4d9dc6SAnna Dabrowska $dictionary = $value->value; 254*dc4d9dc6SAnna Dabrowska $dictionary->value['Length'] = PdfNumeric::create(\strlen($stream)); 255*dc4d9dc6SAnna Dabrowska $value = PdfStream::create($dictionary, $stream); 256*dc4d9dc6SAnna Dabrowska 257*dc4d9dc6SAnna Dabrowska } elseif ($value instanceof PdfIndirectObject) { 258*dc4d9dc6SAnna Dabrowska /** 259*dc4d9dc6SAnna Dabrowska * @var $value PdfIndirectObject 260*dc4d9dc6SAnna Dabrowska */ 261*dc4d9dc6SAnna Dabrowska $this->currentObjectNumber = $this->objectMap[$this->currentReaderId][$value->objectNumber]; 262*dc4d9dc6SAnna Dabrowska } 263*dc4d9dc6SAnna Dabrowska 264*dc4d9dc6SAnna Dabrowska $this->fpdiWritePdfType($value); 265*dc4d9dc6SAnna Dabrowska } 266*dc4d9dc6SAnna Dabrowska}