Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

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