MDL-49515 libraries: Update FPDI to 1.5.4
[moodle.git] / mod / assign / feedback / editpdf / fpdi / fpdi.php
CommitLineData
5c386472
DW
1<?php\r
2//\r
858d457d 3// FPDI - Version 1.5.4\r
5c386472 4//\r
858d457d 5// Copyright 2004-2015 Setasign - Jan Slabon\r
5c386472
DW
6//\r
7// Licensed under the Apache License, Version 2.0 (the "License");\r
8// you may not use this file except in compliance with the License.\r
9// You may obtain a copy of the License at\r
10//\r
11// http://www.apache.org/licenses/LICENSE-2.0\r
12//\r
13// Unless required by applicable law or agreed to in writing, software\r
14// distributed under the License is distributed on an "AS IS" BASIS,\r
15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16// See the License for the specific language governing permissions and\r
17// limitations under the License.\r
18//\r
19\r
858d457d
AG
20if (!class_exists('FPDF_TPL')) {\r
21 require_once('fpdf_tpl.php');\r
5c386472
DW
22}\r
23\r
858d457d
AG
24/**\r
25 * Class FPDI\r
26 */\r
27class FPDI extends FPDF_TPL\r
28{\r
29 /**\r
30 * FPDI version\r
31 *\r
32 * @string\r
33 */\r
34 const VERSION = '1.5.3';\r
5c386472 35\r
5c386472
DW
36 /**\r
37 * Actual filename\r
858d457d 38 *\r
5c386472
DW
39 * @var string\r
40 */\r
858d457d 41 public $currentFilename;\r
5c386472
DW
42\r
43 /**\r
44 * Parser-Objects\r
858d457d
AG
45 *\r
46 * @var fpdi_pdf_parser[]\r
5c386472 47 */\r
858d457d 48 public $parsers = array();\r
5c386472
DW
49 \r
50 /**\r
51 * Current parser\r
858d457d
AG
52 *\r
53 * @var fpdi_pdf_parser\r
5c386472 54 */\r
858d457d
AG
55 public $currentParser;\r
56\r
57 /**\r
58 * The name of the last imported page box\r
59 *\r
60 * @var string\r
61 */\r
62 public $lastUsedPageBox;\r
63\r
5c386472 64 /**\r
858d457d
AG
65 * Object stack\r
66 *\r
5c386472
DW
67 * @var array\r
68 */\r
858d457d 69 protected $_objStack;\r
5c386472
DW
70 \r
71 /**\r
858d457d
AG
72 * Done object stack\r
73 *\r
5c386472
DW
74 * @var array\r
75 */\r
858d457d 76 protected $_doneObjStack;\r
5c386472
DW
77\r
78 /**\r
79 * Current Object Id.\r
858d457d 80 *\r
5c386472
DW
81 * @var integer\r
82 */\r
858d457d 83 protected $_currentObjId;\r
5c386472
DW
84 \r
85 /**\r
86 * Cache for imported pages/template ids\r
858d457d 87 *\r
5c386472
DW
88 * @var array\r
89 */\r
858d457d 90 protected $_importedPages = array();\r
5c386472
DW
91 \r
92 /**\r
858d457d 93 * Set a source-file.\r
5c386472 94 *\r
858d457d
AG
95 * Depending on the PDF version of the used document the PDF version of the resulting document will\r
96 * be adjusted to the higher version.\r
97 *\r
98 * @param string $filename A valid path to the PDF document from which pages should be imported from\r
99 * @return int The number of pages in the document\r
5c386472 100 */\r
858d457d
AG
101 public function setSourceFile($filename)\r
102 {\r
103 $_filename = realpath($filename);\r
104 if (false !== $_filename)\r
105 $filename = $_filename;\r
106\r
107 $this->currentFilename = $filename;\r
5c386472 108 \r
858d457d 109 if (!isset($this->parsers[$filename])) {\r
5c386472 110 $this->parsers[$filename] = $this->_getPdfParser($filename);\r
858d457d
AG
111 $this->setPdfVersion(\r
112 max($this->getPdfVersion(), $this->parsers[$filename]->getPdfVersion())\r
113 );\r
114 }\r
115\r
116 $this->currentParser = $this->parsers[$filename];\r
5c386472
DW
117 \r
118 return $this->parsers[$filename]->getPageCount();\r
119 }\r
120 \r
121 /**\r
122 * Returns a PDF parser object\r
123 *\r
124 * @param string $filename\r
125 * @return fpdi_pdf_parser\r
126 */\r
858d457d
AG
127 protected function _getPdfParser($filename)\r
128 {\r
129 if (!class_exists('fpdi_pdf_parser')) {\r
130 require_once('fpdi_pdf_parser.php');\r
131 }\r
132 return new fpdi_pdf_parser($filename);\r
5c386472
DW
133 }\r
134 \r
135 /**\r
858d457d 136 * Get the current PDF version.\r
5c386472
DW
137 *\r
138 * @return string\r
139 */\r
858d457d
AG
140 public function getPdfVersion()\r
141 {\r
5c386472
DW
142 return $this->PDFVersion;\r
143 }\r
144 \r
858d457d
AG
145 /**\r
146 * Set the PDF version.\r
5c386472 147 *\r
858d457d 148 * @param string $version\r
5c386472 149 */\r
858d457d
AG
150 public function setPdfVersion($version = '1.3')\r
151 {\r
152 $this->PDFVersion = sprintf('%.1F', $version);\r
153 }\r
5c386472
DW
154 \r
155 /**\r
858d457d 156 * Import a page.\r
5c386472 157 *\r
858d457d
AG
158 * The second parameter defines the bounding box that should be used to transform the page into a\r
159 * form XObject.\r
160 *\r
161 * Following values are available: MediaBox, CropBox, BleedBox, TrimBox, ArtBox.\r
162 * If a box is not especially defined its default box will be used:\r
163 *\r
164 * <ul>\r
165 * <li>CropBox: Default -> MediaBox</li>\r
166 * <li>BleedBox: Default -> CropBox</li>\r
167 * <li>TrimBox: Default -> CropBox</li>\r
168 * <li>ArtBox: Default -> CropBox</li>\r
169 * </ul>\r
170 *\r
171 * It is possible to get the used page box by the {@link getLastUsedPageBox()} method.\r
172 *\r
173 * @param int $pageNo The page number\r
174 * @param string $boxName The boundary box to use when transforming the page into a form XObject\r
175 * @param boolean $groupXObject Define the form XObject as a group XObject to support transparency (if used)\r
176 * @return int An id of the imported page/template to use with e.g. fpdf_tpl::useTemplate()\r
177 * @throws LogicException|InvalidArgumentException\r
178 * @see getLastUsedPageBox()\r
5c386472 179 */\r
858d457d
AG
180 public function importPage($pageNo, $boxName = 'CropBox', $groupXObject = true)\r
181 {\r
182 if ($this->_inTpl) {\r
183 throw new LogicException('Please import the desired pages before creating a new template.');\r
5c386472
DW
184 }\r
185 \r
858d457d
AG
186 $fn = $this->currentFilename;\r
187 $boxName = '/' . ltrim($boxName, '/');\r
188\r
5c386472 189 // check if page already imported\r
858d457d
AG
190 $pageKey = $fn . '-' . ((int)$pageNo) . $boxName;\r
191 if (isset($this->_importedPages[$pageKey])) {\r
5c386472 192 return $this->_importedPages[$pageKey];\r
858d457d 193 }\r
5c386472 194 \r
858d457d
AG
195 $parser = $this->parsers[$fn];\r
196 $parser->setPageNo($pageNo);\r
5c386472 197\r
858d457d
AG
198 if (!in_array($boxName, $parser->availableBoxes)) {\r
199 throw new InvalidArgumentException(sprintf('Unknown box: %s', $boxName));\r
200 }\r
5c386472 201 \r
858d457d 202 $pageBoxes = $parser->getPageBoxes($pageNo, $this->k);\r
5c386472
DW
203 \r
204 /**\r
205 * MediaBox\r
206 * CropBox: Default -> MediaBox\r
207 * BleedBox: Default -> CropBox\r
208 * TrimBox: Default -> CropBox\r
209 * ArtBox: Default -> CropBox\r
210 */\r
858d457d 211 if (!isset($pageBoxes[$boxName]) && ($boxName == '/BleedBox' || $boxName == '/TrimBox' || $boxName == '/ArtBox'))\r
5c386472 212 $boxName = '/CropBox';\r
858d457d 213 if (!isset($pageBoxes[$boxName]) && $boxName == '/CropBox')\r
5c386472
DW
214 $boxName = '/MediaBox';\r
215 \r
858d457d 216 if (!isset($pageBoxes[$boxName]))\r
5c386472
DW
217 return false;\r
218 \r
219 $this->lastUsedPageBox = $boxName;\r
220 \r
858d457d 221 $box = $pageBoxes[$boxName];\r
5c386472
DW
222 \r
223 $this->tpl++;\r
858d457d
AG
224 $this->_tpls[$this->tpl] = array();\r
225 $tpl =& $this->_tpls[$this->tpl];\r
226 $tpl['parser'] = $parser;\r
5c386472
DW
227 $tpl['resources'] = $parser->getPageResources();\r
228 $tpl['buffer'] = $parser->getContent();\r
229 $tpl['box'] = $box;\r
858d457d
AG
230 $tpl['groupXObject'] = $groupXObject;\r
231 if ($groupXObject) {\r
232 $this->setPdfVersion(max($this->getPdfVersion(), 1.4));\r
233 }\r
234\r
5c386472 235 // To build an array that can be used by PDF_TPL::useTemplate()\r
858d457d 236 $this->_tpls[$this->tpl] = array_merge($this->_tpls[$this->tpl], $box);\r
5c386472 237 \r
858d457d 238 // An imported page will start at 0,0 all the time. Translation will be set in _putformxobjects()\r
5c386472
DW
239 $tpl['x'] = 0;\r
240 $tpl['y'] = 0;\r
241 \r
242 // handle rotated pages\r
858d457d 243 $rotation = $parser->getPageRotation($pageNo);\r
5c386472
DW
244 $tpl['_rotationAngle'] = 0;\r
245 if (isset($rotation[1]) && ($angle = $rotation[1] % 360) != 0) {\r
246 $steps = $angle / 90;\r
247 \r
248 $_w = $tpl['w'];\r
249 $_h = $tpl['h'];\r
250 $tpl['w'] = $steps % 2 == 0 ? $_w : $_h;\r
251 $tpl['h'] = $steps % 2 == 0 ? $_h : $_w;\r
252 \r
253 if ($angle < 0)\r
254 $angle += 360;\r
255 \r
256 $tpl['_rotationAngle'] = $angle * -1;\r
257 }\r
258 \r
259 $this->_importedPages[$pageKey] = $this->tpl;\r
260 \r
261 return $this->tpl;\r
262 }\r
263 \r
264 /**\r
858d457d 265 * Returns the last used page boundary box.\r
5c386472 266 *\r
858d457d 267 * @return string The used boundary box: MediaBox, CropBox, BleedBox, TrimBox or ArtBox\r
5c386472 268 */\r
858d457d
AG
269 public function getLastUsedPageBox()\r
270 {\r
5c386472
DW
271 return $this->lastUsedPageBox;\r
272 }\r
858d457d
AG
273\r
274 /**\r
275 * Use a template or imported page in current page or other template.\r
276 *\r
277 * You can use a template in a page or in another template.\r
278 * You can give the used template a new size. All parameters are optional.\r
279 * The width or height is calculated automatically if one is given. If no\r
280 * parameter is given the origin size as defined in beginTemplate() or of\r
281 * the imported page is used.\r
282 *\r
283 * The calculated or used width and height are returned as an array.\r
284 *\r
285 * @param int $tplIdx A valid template-id\r
286 * @param int $x The x-position\r
287 * @param int $y The y-position\r
288 * @param int $w The new width of the template\r
289 * @param int $h The new height of the template\r
290 * @param boolean $adjustPageSize If set to true the current page will be resized to fit the dimensions\r
291 * of the template\r
292 *\r
293 * @return array The height and width of the template (array('w' => ..., 'h' => ...))\r
294 * @throws LogicException|InvalidArgumentException\r
295 */\r
296 public function useTemplate($tplIdx, $x = null, $y = null, $w = 0, $h = 0, $adjustPageSize = false)\r
297 {\r
298 if ($adjustPageSize == true && is_null($x) && is_null($y)) {\r
299 $size = $this->getTemplateSize($tplIdx, $w, $h);\r
5c386472
DW
300 $orientation = $size['w'] > $size['h'] ? 'L' : 'P';\r
301 $size = array($size['w'], $size['h']);\r
302 \r
303 if (is_subclass_of($this, 'TCPDF')) {\r
304 $this->setPageFormat($size, $orientation);\r
305 } else {\r
306 $size = $this->_getpagesize($size);\r
307 \r
858d457d
AG
308 if($orientation != $this->CurOrientation ||\r
309 $size[0] != $this->CurPageSize[0] ||\r
310 $size[1] != $this->CurPageSize[1]\r
311 ) {\r
5c386472 312 // New size or orientation\r
858d457d 313 if ($orientation=='P') {\r
5c386472
DW
314 $this->w = $size[0];\r
315 $this->h = $size[1];\r
858d457d 316 } else {\r
5c386472
DW
317 $this->w = $size[1];\r
318 $this->h = $size[0];\r
319 }\r
858d457d
AG
320 $this->wPt = $this->w * $this->k;\r
321 $this->hPt = $this->h * $this->k;\r
322 $this->PageBreakTrigger = $this->h - $this->bMargin;\r
5c386472
DW
323 $this->CurOrientation = $orientation;\r
324 $this->CurPageSize = $size;\r
325 $this->PageSizes[$this->page] = array($this->wPt, $this->hPt);\r
326 }\r
327 } \r
328 }\r
329 \r
330 $this->_out('q 0 J 1 w 0 j 0 G 0 g'); // reset standard values\r
858d457d 331 $size = parent::useTemplate($tplIdx, $x, $y, $w, $h);\r
5c386472
DW
332 $this->_out('Q');\r
333 \r
858d457d 334 return $size;\r
5c386472
DW
335 }\r
336 \r
337 /**\r
858d457d 338 * Copy all imported objects to the resulting document.\r
5c386472 339 */\r
858d457d
AG
340 protected function _putimportedobjects()\r
341 {\r
342 foreach($this->parsers AS $filename => $p) {\r
343 $this->currentParser = $p;\r
344 if (!isset($this->_objStack[$filename]) || !is_array($this->_objStack[$filename])) {\r
345 continue;\r
346 }\r
347 while(($n = key($this->_objStack[$filename])) !== null) {\r
348 try {\r
349 $nObj = $this->currentParser->resolveObject($this->_objStack[$filename][$n][1]);\r
350 } catch (Exception $e) {\r
351 $nObj = array(pdf_parser::TYPE_OBJECT, pdf_parser::TYPE_NULL);\r
5c386472 352 }\r
858d457d
AG
353\r
354 $this->_newobj($this->_objStack[$filename][$n][0]);\r
355\r
356 if ($nObj[0] == pdf_parser::TYPE_STREAM) {\r
357 $this->_writeValue($nObj);\r
358 } else {\r
359 $this->_writeValue($nObj[1]);\r
360 }\r
361\r
362 $this->_out("\nendobj");\r
363 $this->_objStack[$filename][$n] = null; // free memory\r
364 unset($this->_objStack[$filename][$n]);\r
365 reset($this->_objStack[$filename]);\r
5c386472
DW
366 }\r
367 }\r
368 }\r
858d457d 369\r
5c386472 370 /**\r
858d457d 371 * Writes the form XObjects to the PDF document.\r
5c386472 372 */\r
858d457d
AG
373 protected function _putformxobjects()\r
374 {\r
375 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';\r
376 reset($this->_tpls);\r
377 foreach($this->_tpls AS $tplIdx => $tpl) {\r
378 $this->_newobj();\r
379 $currentN = $this->n; // TCPDF/Protection: rem current "n"\r
5c386472 380 \r
858d457d 381 $this->_tpls[$tplIdx]['n'] = $this->n;\r
5c386472
DW
382 $this->_out('<<' . $filter . '/Type /XObject');\r
383 $this->_out('/Subtype /Form');\r
384 $this->_out('/FormType 1');\r
385 \r
386 $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]', \r
387 (isset($tpl['box']['llx']) ? $tpl['box']['llx'] : $tpl['x']) * $this->k,\r
388 (isset($tpl['box']['lly']) ? $tpl['box']['lly'] : -$tpl['y']) * $this->k,\r
389 (isset($tpl['box']['urx']) ? $tpl['box']['urx'] : $tpl['w'] + $tpl['x']) * $this->k,\r
390 (isset($tpl['box']['ury']) ? $tpl['box']['ury'] : $tpl['h'] - $tpl['y']) * $this->k\r
391 ));\r
392 \r
393 $c = 1;\r
394 $s = 0;\r
395 $tx = 0;\r
396 $ty = 0;\r
397 \r
398 if (isset($tpl['box'])) {\r
399 $tx = -$tpl['box']['llx'];\r
400 $ty = -$tpl['box']['lly']; \r
401 \r
402 if ($tpl['_rotationAngle'] <> 0) {\r
403 $angle = $tpl['_rotationAngle'] * M_PI/180;\r
858d457d
AG
404 $c = cos($angle);\r
405 $s = sin($angle);\r
5c386472
DW
406 \r
407 switch($tpl['_rotationAngle']) {\r
408 case -90:\r
409 $tx = -$tpl['box']['lly'];\r
410 $ty = $tpl['box']['urx'];\r
411 break;\r
412 case -180:\r
413 $tx = $tpl['box']['urx'];\r
414 $ty = $tpl['box']['ury'];\r
415 break;\r
416 case -270:\r
417 $tx = $tpl['box']['ury'];\r
418 $ty = -$tpl['box']['llx'];\r
419 break;\r
420 }\r
421 }\r
858d457d 422 } else if ($tpl['x'] != 0 || $tpl['y'] != 0) {\r
5c386472
DW
423 $tx = -$tpl['x'] * 2;\r
424 $ty = $tpl['y'] * 2;\r
425 }\r
426 \r
427 $tx *= $this->k;\r
428 $ty *= $this->k;\r
429 \r
430 if ($c != 1 || $s != 0 || $tx != 0 || $ty != 0) {\r
431 $this->_out(sprintf('/Matrix [%.5F %.5F %.5F %.5F %.5F %.5F]',\r
432 $c, $s, -$s, $c, $tx, $ty\r
433 ));\r
434 }\r
435 \r
436 $this->_out('/Resources ');\r
437\r
438 if (isset($tpl['resources'])) {\r
858d457d
AG
439 $this->currentParser = $tpl['parser'];\r
440 $this->_writeValue($tpl['resources']); // "n" will be changed\r
5c386472 441 } else {\r
858d457d 442\r
5c386472 443 $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');\r
858d457d
AG
444 if (isset($this->_res['tpl'][$tplIdx])) {\r
445 $res = $this->_res['tpl'][$tplIdx];\r
446\r
447 if (isset($res['fonts']) && count($res['fonts'])) {\r
448 $this->_out('/Font <<');\r
449 foreach ($res['fonts'] as $font)\r
450 $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');\r
451 $this->_out('>>');\r
5c386472 452 }\r
858d457d
AG
453 if (isset($res['images']) && count($res['images']) ||\r
454 isset($res['tpls']) && count($res['tpls']))\r
455 {\r
456 $this->_out('/XObject <<');\r
457 if (isset($res['images'])) {\r
458 foreach ($res['images'] as $image)\r
459 $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');\r
460 }\r
461 if (isset($res['tpls'])) {\r
462 foreach ($res['tpls'] as $i => $_tpl)\r
463 $this->_out($this->tplPrefix . $i . ' ' . $_tpl['n'] . ' 0 R');\r
464 }\r
465 $this->_out('>>');\r
5c386472
DW
466 }\r
467 $this->_out('>>');\r
858d457d 468 }\r
5c386472 469 }\r
858d457d
AG
470\r
471 if (isset($tpl['groupXObject']) && $tpl['groupXObject']) {\r
472 $this->_out('/Group <</Type/Group/S/Transparency>>');\r
473 }\r
474\r
475 $newN = $this->n; // TCPDF: rem new "n"\r
476 $this->n = $currentN; // TCPDF: reset to current "n"\r
477\r
478 $buffer = ($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer'];\r
479\r
5c386472 480 if (is_subclass_of($this, 'TCPDF')) {\r
858d457d
AG
481 $buffer = $this->_getrawstream($buffer);\r
482 $this->_out('/Length ' . strlen($buffer) . ' >>');\r
483 $this->_out("stream\n" . $buffer . "\nendstream");\r
5c386472 484 } else {\r
858d457d
AG
485 $this->_out('/Length ' . strlen($buffer) . ' >>');\r
486 $this->_putstream($buffer);\r
5c386472
DW
487 }\r
488 $this->_out('endobj');\r
858d457d 489 $this->n = $newN; // TCPDF: reset to new "n"\r
5c386472
DW
490 }\r
491 \r
492 $this->_putimportedobjects();\r
493 }\r
494\r
495 /**\r
858d457d
AG
496 * Creates and optionally write the object definition to the document.\r
497 *\r
5c386472 498 * Rewritten to handle existing own defined objects\r
858d457d
AG
499 *\r
500 * @param bool $objId\r
501 * @param bool $onlyNewObj\r
502 * @return bool|int\r
5c386472 503 */\r
858d457d
AG
504 public function _newobj($objId = false, $onlyNewObj = false)\r
505 {\r
506 if (!$objId) {\r
507 $objId = ++$this->n;\r
5c386472
DW
508 }\r
509\r
510 //Begin a new object\r
858d457d
AG
511 if (!$onlyNewObj) {\r
512 $this->offsets[$objId] = is_subclass_of($this, 'TCPDF') ? $this->bufferlen : strlen($this->buffer);\r
513 $this->_out($objId . ' 0 obj');\r
514 $this->_currentObjId = $objId; // for later use with encryption\r
5c386472
DW
515 }\r
516 \r
858d457d 517 return $objId;\r
5c386472
DW
518 }\r
519\r
520 /**\r
858d457d
AG
521 * Writes a PDF value to the resulting document.\r
522 *\r
5c386472
DW
523 * Needed to rebuild the source document\r
524 *\r
525 * @param mixed $value A PDF-Value. Structure of values see cases in this method\r
526 */\r
858d457d 527 protected function _writeValue(&$value)\r
5c386472
DW
528 {\r
529 if (is_subclass_of($this, 'TCPDF')) {\r
858d457d 530 parent::_prepareValue($value);\r
5c386472
DW
531 }\r
532 \r
533 switch ($value[0]) {\r
534\r
858d457d 535 case pdf_parser::TYPE_TOKEN:\r
5c386472
DW
536 $this->_straightOut($value[1] . ' ');\r
537 break;\r
858d457d
AG
538 case pdf_parser::TYPE_NUMERIC:\r
539 case pdf_parser::TYPE_REAL:\r
5c386472
DW
540 if (is_float($value[1]) && $value[1] != 0) {\r
541 $this->_straightOut(rtrim(rtrim(sprintf('%F', $value[1]), '0'), '.') . ' ');\r
542 } else {\r
543 $this->_straightOut($value[1] . ' ');\r
544 }\r
545 break;\r
546 \r
858d457d 547 case pdf_parser::TYPE_ARRAY:\r
5c386472
DW
548\r
549 // An array. Output the proper\r
550 // structure and move on.\r
551\r
552 $this->_straightOut('[');\r
553 for ($i = 0; $i < count($value[1]); $i++) {\r
858d457d 554 $this->_writeValue($value[1][$i]);\r
5c386472
DW
555 }\r
556\r
557 $this->_out(']');\r
558 break;\r
559\r
858d457d 560 case pdf_parser::TYPE_DICTIONARY:\r
5c386472
DW
561\r
562 // A dictionary.\r
563 $this->_straightOut('<<');\r
564\r
565 reset ($value[1]);\r
566\r
567 while (list($k, $v) = each($value[1])) {\r
568 $this->_straightOut($k . ' ');\r
858d457d 569 $this->_writeValue($v);\r
5c386472
DW
570 }\r
571\r
572 $this->_straightOut('>>');\r
573 break;\r
574\r
858d457d 575 case pdf_parser::TYPE_OBJREF:\r
5c386472
DW
576\r
577 // An indirect object reference\r
578 // Fill the object stack if needed\r
858d457d
AG
579 $cpfn =& $this->currentParser->filename;\r
580 if (!isset($this->_doneObjStack[$cpfn][$value[1]])) {\r
5c386472 581 $this->_newobj(false, true);\r
858d457d
AG
582 $this->_objStack[$cpfn][$value[1]] = array($this->n, $value);\r
583 $this->_doneObjStack[$cpfn][$value[1]] = array($this->n, $value);\r
5c386472 584 }\r
858d457d 585 $objId = $this->_doneObjStack[$cpfn][$value[1]][0];\r
5c386472 586\r
858d457d 587 $this->_out($objId . ' 0 R');\r
5c386472
DW
588 break;\r
589\r
858d457d 590 case pdf_parser::TYPE_STRING:\r
5c386472
DW
591\r
592 // A string.\r
593 $this->_straightOut('(' . $value[1] . ')');\r
594\r
595 break;\r
596\r
858d457d 597 case pdf_parser::TYPE_STREAM:\r
5c386472
DW
598\r
599 // A stream. First, output the\r
600 // stream dictionary, then the\r
601 // stream data itself.\r
858d457d 602 $this->_writeValue($value[1]);\r
5c386472
DW
603 $this->_out('stream');\r
604 $this->_out($value[2][1]);\r
858d457d 605 $this->_straightOut("endstream");\r
5c386472
DW
606 break;\r
607 \r
858d457d 608 case pdf_parser::TYPE_HEX:\r
5c386472
DW
609 $this->_straightOut('<' . $value[1] . '>');\r
610 break;\r
611\r
858d457d 612 case pdf_parser::TYPE_BOOLEAN:\r
5c386472
DW
613 $this->_straightOut($value[1] ? 'true ' : 'false ');\r
614 break;\r
615 \r
858d457d 616 case pdf_parser::TYPE_NULL:\r
5c386472
DW
617 // The null object.\r
618\r
619 $this->_straightOut('null ');\r
620 break;\r
621 }\r
622 }\r
623 \r
624 \r
625 /**\r
858d457d 626 * Modified _out() method so not each call will add a newline to the output.\r
5c386472 627 */\r
858d457d
AG
628 protected function _straightOut($s)\r
629 {\r
5c386472 630 if (!is_subclass_of($this, 'TCPDF')) {\r
858d457d 631 if ($this->state == 2) {\r
5c386472 632 $this->pages[$this->page] .= $s;\r
858d457d 633 } else {\r
5c386472 634 $this->buffer .= $s;\r
858d457d
AG
635 }\r
636\r
5c386472
DW
637 } else {\r
638 if ($this->state == 2) {\r
639 if ($this->inxobj) {\r
640 // we are inside an XObject template\r
641 $this->xobjects[$this->xobjid]['outdata'] .= $s;\r
858d457d 642 } else if ((!$this->InFooter) AND isset($this->footerlen[$this->page]) AND ($this->footerlen[$this->page] > 0)) {\r
5c386472
DW
643 // puts data before page footer\r
644 $pagebuff = $this->getPageBuffer($this->page);\r
645 $page = substr($pagebuff, 0, -$this->footerlen[$this->page]);\r
646 $footer = substr($pagebuff, -$this->footerlen[$this->page]);\r
858d457d 647 $this->setPageBuffer($this->page, $page . $s . $footer);\r
5c386472
DW
648 // update footer position\r
649 $this->footerpos[$this->page] += strlen($s);\r
650 } else {\r
651 // set page data\r
652 $this->setPageBuffer($this->page, $s, true);\r
653 }\r
858d457d 654 } else if ($this->state > 0) {\r
5c386472
DW
655 // set general data\r
656 $this->setBuffer($s);\r
657 }\r
658 }\r
659 }\r
660\r
661 /**\r
858d457d 662 * Ends the document\r
5c386472 663 *\r
858d457d 664 * Overwritten to close opened parsers\r
5c386472 665 */\r
858d457d
AG
666 public function _enddoc()\r
667 {\r
5c386472
DW
668 parent::_enddoc();\r
669 $this->_closeParsers();\r
670 }\r
671 \r
672 /**\r
858d457d
AG
673 * Close all files opened by parsers.\r
674 *\r
675 * @return boolean\r
5c386472 676 */\r
858d457d
AG
677 protected function _closeParsers()\r
678 {\r
679 if ($this->state > 2) {\r
5c386472
DW
680 $this->cleanUp();\r
681 return true;\r
682 }\r
858d457d 683\r
5c386472
DW
684 return false;\r
685 }\r
686 \r
687 /**\r
858d457d 688 * Removes cycled references and closes the file handles of the parser objects.\r
5c386472 689 */\r
858d457d
AG
690 public function cleanUp()\r
691 {\r
692 while (($parser = array_pop($this->parsers)) !== null) {\r
693 /**\r
694 * @var fpdi_pdf_parser $parser\r
695 */\r
696 $parser->closeFile();\r
5c386472
DW
697 }\r
698 }\r
699}