File indexing completed on 2024-12-22 05:36:57
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Pdf 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** Internally used classes */ 0023 // require_once 'Zend/Pdf/Element.php'; 0024 // require_once 'Zend/Pdf/Element/Array.php'; 0025 // require_once 'Zend/Pdf/Element/String/Binary.php'; 0026 // require_once 'Zend/Pdf/Element/Boolean.php'; 0027 // require_once 'Zend/Pdf/Element/Dictionary.php'; 0028 // require_once 'Zend/Pdf/Element/Name.php'; 0029 // require_once 'Zend/Pdf/Element/Null.php'; 0030 // require_once 'Zend/Pdf/Element/Numeric.php'; 0031 // require_once 'Zend/Pdf/Element/String.php'; 0032 // require_once 'Zend/Pdf/Resource/Unified.php'; 0033 0034 // require_once 'Zend/Pdf/Canvas/Abstract.php'; 0035 0036 0037 /** 0038 * PDF Page 0039 * 0040 * @package Zend_Pdf 0041 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0042 * @license http://framework.zend.com/license/new-bsd New BSD License 0043 */ 0044 class Zend_Pdf_Page extends Zend_Pdf_Canvas_Abstract 0045 { 0046 /**** Class Constants ****/ 0047 0048 0049 /* Page Sizes */ 0050 0051 /** 0052 * Size representing an A4 page in portrait (tall) orientation. 0053 */ 0054 const SIZE_A4 = '595:842:'; 0055 0056 /** 0057 * Size representing an A4 page in landscape (wide) orientation. 0058 */ 0059 const SIZE_A4_LANDSCAPE = '842:595:'; 0060 0061 /** 0062 * Size representing a US Letter page in portrait (tall) orientation. 0063 */ 0064 const SIZE_LETTER = '612:792:'; 0065 0066 /** 0067 * Size representing a US Letter page in landscape (wide) orientation. 0068 */ 0069 const SIZE_LETTER_LANDSCAPE = '792:612:'; 0070 0071 0072 /* Shape Drawing */ 0073 0074 /** 0075 * Stroke the path only. Do not fill. 0076 */ 0077 const SHAPE_DRAW_STROKE = 0; 0078 0079 /** 0080 * Fill the path only. Do not stroke. 0081 */ 0082 const SHAPE_DRAW_FILL = 1; 0083 0084 /** 0085 * Fill and stroke the path. 0086 */ 0087 const SHAPE_DRAW_FILL_AND_STROKE = 2; 0088 0089 0090 /* Shape Filling Methods */ 0091 0092 /** 0093 * Fill the path using the non-zero winding rule. 0094 */ 0095 const FILL_METHOD_NON_ZERO_WINDING = 0; 0096 0097 /** 0098 * Fill the path using the even-odd rule. 0099 */ 0100 const FILL_METHOD_EVEN_ODD = 1; 0101 0102 0103 /* Line Dash Types */ 0104 0105 /** 0106 * Solid line dash. 0107 */ 0108 const LINE_DASHING_SOLID = 0; 0109 0110 0111 0112 /** 0113 * Page dictionary (refers to an inderect Zend_Pdf_Element_Dictionary object). 0114 * 0115 * @var Zend_Pdf_Element_Reference|Zend_Pdf_Element_Object 0116 */ 0117 protected $_dictionary; 0118 0119 /** 0120 * PDF objects factory. 0121 * 0122 * @var Zend_Pdf_ElementFactory_Interface 0123 */ 0124 protected $_objFactory = null; 0125 0126 /** 0127 * Flag which signals, that page is created separately from any PDF document or 0128 * attached to anyone. 0129 * 0130 * @var boolean 0131 */ 0132 protected $_attached; 0133 0134 /** 0135 * Safe Graphics State semafore 0136 * 0137 * If it's false, than we can't be sure Graphics State is restored withing 0138 * context of previous contents stream (ex. drawing coordinate system may be rotated). 0139 * We should encompass existing content with save/restore GS operators 0140 * 0141 * @var boolean 0142 */ 0143 protected $_safeGS; 0144 0145 /** 0146 * Object constructor. 0147 * Constructor signatures: 0148 * 0149 * 1. Load PDF page from a parsed PDF file. 0150 * Object factory is created by PDF parser. 0151 * --------------------------------------------------------- 0152 * new Zend_Pdf_Page(Zend_Pdf_Element_Dictionary $pageDict, 0153 * Zend_Pdf_ElementFactory_Interface $factory); 0154 * --------------------------------------------------------- 0155 * 0156 * 2. Make a copy of the PDF page. 0157 * New page is created in the same context as source page. Object factory is shared. 0158 * Thus it will be attached to the document, but need to be placed into Zend_Pdf::$pages array 0159 * to be included into output. 0160 * --------------------------------------------------------- 0161 * new Zend_Pdf_Page(Zend_Pdf_Page $page); 0162 * --------------------------------------------------------- 0163 * 0164 * 3. Create new page with a specified pagesize. 0165 * If $factory is null then it will be created and page must be attached to the document to be 0166 * included into output. 0167 * --------------------------------------------------------- 0168 * new Zend_Pdf_Page(string $pagesize, Zend_Pdf_ElementFactory_Interface $factory = null); 0169 * --------------------------------------------------------- 0170 * 0171 * 4. Create new page with a specified pagesize (in default user space units). 0172 * If $factory is null then it will be created and page must be attached to the document to be 0173 * included into output. 0174 * --------------------------------------------------------- 0175 * new Zend_Pdf_Page(numeric $width, numeric $height, Zend_Pdf_ElementFactory_Interface $factory = null); 0176 * --------------------------------------------------------- 0177 * 0178 * 0179 * @param mixed $param1 0180 * @param mixed $param2 0181 * @param mixed $param3 0182 * @throws Zend_Pdf_Exception 0183 */ 0184 public function __construct($param1, $param2 = null, $param3 = null) 0185 { 0186 if (($param1 instanceof Zend_Pdf_Element_Reference || 0187 $param1 instanceof Zend_Pdf_Element_Object 0188 ) && 0189 $param2 instanceof Zend_Pdf_ElementFactory_Interface && 0190 $param3 === null 0191 ) { 0192 switch ($param1->getType()) { 0193 case Zend_Pdf_Element::TYPE_DICTIONARY: 0194 $this->_dictionary = $param1; 0195 $this->_objFactory = $param2; 0196 $this->_attached = true; 0197 $this->_safeGS = false; 0198 return; 0199 break; 0200 0201 case Zend_Pdf_Element::TYPE_NULL: 0202 $this->_objFactory = $param2; 0203 $pageWidth = $pageHeight = 0; 0204 break; 0205 0206 default: 0207 // require_once 'Zend/Pdf/Exception.php'; 0208 throw new Zend_Pdf_Exception('Unrecognized object type.'); 0209 break; 0210 0211 } 0212 } else if ($param1 instanceof Zend_Pdf_Page && $param2 === null && $param3 === null) { 0213 // Duplicate existing page. 0214 // Let already existing content and resources to be shared between pages 0215 // We don't give existing content modification functionality, so we don't need "deep copy" 0216 $this->_objFactory = $param1->_objFactory; 0217 $this->_attached = &$param1->_attached; 0218 $this->_safeGS = false; 0219 0220 $this->_dictionary = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); 0221 0222 foreach ($param1->_dictionary->getKeys() as $key) { 0223 if ($key == 'Contents') { 0224 // Clone Contents property 0225 0226 $this->_dictionary->Contents = new Zend_Pdf_Element_Array(); 0227 0228 if ($param1->_dictionary->Contents->getType() != Zend_Pdf_Element::TYPE_ARRAY) { 0229 // Prepare array of content streams and add existing stream 0230 $this->_dictionary->Contents->items[] = $param1->_dictionary->Contents; 0231 } else { 0232 // Clone array of the content streams 0233 foreach ($param1->_dictionary->Contents->items as $srcContentStream) { 0234 $this->_dictionary->Contents->items[] = $srcContentStream; 0235 } 0236 } 0237 } else { 0238 $this->_dictionary->$key = $param1->_dictionary->$key; 0239 } 0240 } 0241 0242 return; 0243 } else if (is_string($param1) && 0244 ($param2 === null || $param2 instanceof Zend_Pdf_ElementFactory_Interface) && 0245 $param3 === null) { 0246 if ($param2 !== null) { 0247 $this->_objFactory = $param2; 0248 } else { 0249 // require_once 'Zend/Pdf/ElementFactory.php'; 0250 $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); 0251 } 0252 $this->_attached = false; 0253 $this->_safeGS = true; /** New page created. That's users App responsibility to track GS changes */ 0254 0255 switch (strtolower($param1)) { 0256 case 'a4': 0257 $param1 = Zend_Pdf_Page::SIZE_A4; 0258 break; 0259 case 'a4-landscape': 0260 $param1 = Zend_Pdf_Page::SIZE_A4_LANDSCAPE; 0261 break; 0262 case 'letter': 0263 $param1 = Zend_Pdf_Page::SIZE_LETTER; 0264 break; 0265 case 'letter-landscape': 0266 $param1 = Zend_Pdf_Page::SIZE_LETTER_LANDSCAPE; 0267 break; 0268 default: 0269 // should be in "x:y" or "x:y:" form 0270 } 0271 0272 $pageDim = explode(':', $param1); 0273 if(count($pageDim) == 2 || count($pageDim) == 3) { 0274 $pageWidth = $pageDim[0]; 0275 $pageHeight = $pageDim[1]; 0276 } else { 0277 /** 0278 * @todo support of user defined pagesize notations, like: 0279 * "210x297mm", "595x842", "8.5x11in", "612x792" 0280 */ 0281 // require_once 'Zend/Pdf/Exception.php'; 0282 throw new Zend_Pdf_Exception('Wrong pagesize notation.'); 0283 } 0284 /** 0285 * @todo support of pagesize recalculation to "default user space units" 0286 */ 0287 0288 } else if (is_numeric($param1) && is_numeric($param2) && 0289 ($param3 === null || $param3 instanceof Zend_Pdf_ElementFactory_Interface)) { 0290 if ($param3 !== null) { 0291 $this->_objFactory = $param3; 0292 } else { 0293 // require_once 'Zend/Pdf/ElementFactory.php'; 0294 $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); 0295 } 0296 0297 $this->_attached = false; 0298 $this->_safeGS = true; /** New page created. That's users App responsibility to track GS changes */ 0299 $pageWidth = $param1; 0300 $pageHeight = $param2; 0301 0302 } else { 0303 // require_once 'Zend/Pdf/Exception.php'; 0304 throw new Zend_Pdf_Exception('Unrecognized method signature, wrong number of arguments or wrong argument types.'); 0305 } 0306 0307 $this->_dictionary = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); 0308 $this->_dictionary->Type = new Zend_Pdf_Element_Name('Page'); 0309 // require_once 'Zend/Pdf.php'; 0310 $this->_dictionary->LastModified = new Zend_Pdf_Element_String(Zend_Pdf::pdfDate()); 0311 $this->_dictionary->Resources = new Zend_Pdf_Element_Dictionary(); 0312 $this->_dictionary->MediaBox = new Zend_Pdf_Element_Array(); 0313 $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0); 0314 $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0); 0315 $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageWidth); 0316 $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageHeight); 0317 $this->_dictionary->Contents = new Zend_Pdf_Element_Array(); 0318 } 0319 0320 0321 /** 0322 * Attach resource to the canvas 0323 * 0324 * Method returns a name of the resource which can be used 0325 * as a resource reference within drawing instructions stream 0326 * Allowed types: 'ExtGState', 'ColorSpace', 'Pattern', 'Shading', 0327 * 'XObject', 'Font', 'Properties' 0328 * 0329 * @param string $type 0330 * @param Zend_Pdf_Resource $resource 0331 * @return string 0332 */ 0333 protected function _attachResource($type, Zend_Pdf_Resource $resource) 0334 { 0335 // Check that Resources dictionary contains appropriate resource set 0336 if ($this->_dictionary->Resources->$type === null) { 0337 $this->_dictionary->Resources->touch(); 0338 $this->_dictionary->Resources->$type = new Zend_Pdf_Element_Dictionary(); 0339 } else { 0340 $this->_dictionary->Resources->$type->touch(); 0341 } 0342 0343 // Check, that resource is already attached to resource set. 0344 $resObject = $resource->getResource(); 0345 foreach ($this->_dictionary->Resources->$type->getKeys() as $ResID) { 0346 if ($this->_dictionary->Resources->$type->$ResID === $resObject) { 0347 return $ResID; 0348 } 0349 } 0350 0351 $idCounter = 1; 0352 do { 0353 $newResName = $type[0] . $idCounter++; 0354 } while ($this->_dictionary->Resources->$type->$newResName !== null); 0355 0356 $this->_dictionary->Resources->$type->$newResName = $resObject; 0357 $this->_objFactory->attach($resource->getFactory()); 0358 0359 return $newResName; 0360 } 0361 0362 /** 0363 * Add procedureSet to the Page description 0364 * 0365 * @param string $procSetName 0366 */ 0367 protected function _addProcSet($procSetName) 0368 { 0369 // Check that Resources dictionary contains ProcSet entry 0370 if ($this->_dictionary->Resources->ProcSet === null) { 0371 $this->_dictionary->Resources->touch(); 0372 $this->_dictionary->Resources->ProcSet = new Zend_Pdf_Element_Array(); 0373 } else { 0374 $this->_dictionary->Resources->ProcSet->touch(); 0375 } 0376 0377 foreach ($this->_dictionary->Resources->ProcSet->items as $procSetEntry) { 0378 if ($procSetEntry->value == $procSetName) { 0379 // Procset is already included into a ProcSet array 0380 return; 0381 } 0382 } 0383 0384 $this->_dictionary->Resources->ProcSet->items[] = new Zend_Pdf_Element_Name($procSetName); 0385 } 0386 0387 /** 0388 * Returns dictionaries of used resources. 0389 * 0390 * Used for canvas implementations interoperability 0391 * 0392 * Structure of the returned array: 0393 * array( 0394 * <resTypeName> => array( 0395 * <resName> => <Zend_Pdf_Resource object>, 0396 * <resName> => <Zend_Pdf_Resource object>, 0397 * <resName> => <Zend_Pdf_Resource object>, 0398 * ... 0399 * ), 0400 * <resTypeName> => array( 0401 * <resName> => <Zend_Pdf_Resource object>, 0402 * <resName> => <Zend_Pdf_Resource object>, 0403 * <resName> => <Zend_Pdf_Resource object>, 0404 * ... 0405 * ), 0406 * ... 0407 * 'ProcSet' => array() 0408 * ) 0409 * 0410 * where ProcSet array is a list of used procedure sets names (strings). 0411 * Allowed procedure set names: 'PDF', 'Text', 'ImageB', 'ImageC', 'ImageI' 0412 * 0413 * @internal 0414 * @return array 0415 */ 0416 public function getResources() 0417 { 0418 $resources = array(); 0419 $resDictionary = $this->_dictionary->Resources; 0420 0421 foreach ($resDictionary->getKeys() as $resType) { 0422 $resources[$resType] = array(); 0423 0424 if ($resType == 'ProcSet') { 0425 foreach ($resDictionary->ProcSet->items as $procSetEntry) { 0426 $resources[$resType][] = $procSetEntry->value; 0427 } 0428 } else { 0429 $resMap = $resDictionary->$resType; 0430 0431 foreach ($resMap->getKeys() as $resId) { 0432 $resources[$resType][$resId] =new Zend_Pdf_Resource_Unified($resMap->$resId); 0433 } 0434 } 0435 } 0436 0437 return $resources; 0438 } 0439 0440 /** 0441 * Get drawing instructions stream 0442 * 0443 * It has to be returned as a PDF stream object to make it reusable. 0444 * 0445 * @internal 0446 * @returns Zend_Pdf_Resource_ContentStream 0447 */ 0448 public function getContents() 0449 { 0450 /** @todo implementation */ 0451 } 0452 0453 /** 0454 * Return the height of this page in points. 0455 * 0456 * @return float 0457 */ 0458 public function getHeight() 0459 { 0460 return $this->_dictionary->MediaBox->items[3]->value - 0461 $this->_dictionary->MediaBox->items[1]->value; 0462 } 0463 0464 /** 0465 * Return the width of this page in points. 0466 * 0467 * @return float 0468 */ 0469 public function getWidth() 0470 { 0471 return $this->_dictionary->MediaBox->items[2]->value - 0472 $this->_dictionary->MediaBox->items[0]->value; 0473 } 0474 0475 /** 0476 * Clone page, extract it and dependent objects from the current document, 0477 * so it can be used within other docs. 0478 */ 0479 public function __clone() 0480 { 0481 $factory = Zend_Pdf_ElementFactory::createFactory(1); 0482 $processed = array(); 0483 0484 // Clone dictionary object. 0485 // Do it explicitly to prevent sharing page attributes between different 0486 // results of clonePage() operation (other resources are still shared) 0487 $dictionary = new Zend_Pdf_Element_Dictionary(); 0488 foreach ($this->_dictionary->getKeys() as $key) { 0489 $dictionary->$key = $this->_dictionary->$key->makeClone($factory->getFactory(), 0490 $processed, 0491 Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES); 0492 } 0493 0494 $this->_dictionary = $factory->newObject($dictionary); 0495 $this->_objFactory = $factory; 0496 $this->_attached = false; 0497 $this->_style = null; 0498 $this->_font = null; 0499 } 0500 0501 /** 0502 * Clone page, extract it and dependent objects from the current document, 0503 * so it can be used within other docs. 0504 * 0505 * @internal 0506 * @param Zend_Pdf_ElementFactory_Interface $factory 0507 * @param array $processed 0508 * @return Zend_Pdf_Page 0509 */ 0510 public function clonePage($factory, &$processed) 0511 { 0512 // Clone dictionary object. 0513 // Do it explicitly to prevent sharing page attributes between different 0514 // results of clonePage() operation (other resources are still shared) 0515 $dictionary = new Zend_Pdf_Element_Dictionary(); 0516 foreach ($this->_dictionary->getKeys() as $key) { 0517 $dictionary->$key = $this->_dictionary->$key->makeClone($factory->getFactory(), 0518 $processed, 0519 Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES); 0520 } 0521 0522 $clonedPage = new Zend_Pdf_Page($factory->newObject($dictionary), $factory); 0523 $clonedPage->_attached = false; 0524 0525 return $clonedPage; 0526 } 0527 0528 /** 0529 * Retrive PDF file reference to the page 0530 * 0531 * @internal 0532 * @return Zend_Pdf_Element_Dictionary 0533 */ 0534 public function getPageDictionary() 0535 { 0536 return $this->_dictionary; 0537 } 0538 0539 /** 0540 * Dump current drawing instructions into the content stream. 0541 * 0542 * @todo Don't forget to close all current graphics operations (like path drawing) 0543 * 0544 * @throws Zend_Pdf_Exception 0545 */ 0546 public function flush() 0547 { 0548 if ($this->_saveCount != 0) { 0549 // require_once 'Zend/Pdf/Exception.php'; 0550 throw new Zend_Pdf_Exception('Saved graphics state is not restored'); 0551 } 0552 0553 if ($this->_contents == '') { 0554 return; 0555 } 0556 0557 if ($this->_dictionary->Contents->getType() != Zend_Pdf_Element::TYPE_ARRAY) { 0558 /** 0559 * It's a stream object. 0560 * Prepare Contents page attribute for update. 0561 */ 0562 $this->_dictionary->touch(); 0563 0564 $currentPageContents = $this->_dictionary->Contents; 0565 $this->_dictionary->Contents = new Zend_Pdf_Element_Array(); 0566 $this->_dictionary->Contents->items[] = $currentPageContents; 0567 } else { 0568 $this->_dictionary->Contents->touch(); 0569 } 0570 0571 if ((!$this->_safeGS) && (count($this->_dictionary->Contents->items) != 0)) { 0572 /** 0573 * Page already has some content which is not treated as safe. 0574 * 0575 * Add save/restore GS operators 0576 */ 0577 $this->_addProcSet('PDF'); 0578 0579 $newContentsArray = new Zend_Pdf_Element_Array(); 0580 $newContentsArray->items[] = $this->_objFactory->newStreamObject(" q\n"); 0581 foreach ($this->_dictionary->Contents->items as $contentStream) { 0582 $newContentsArray->items[] = $contentStream; 0583 } 0584 $newContentsArray->items[] = $this->_objFactory->newStreamObject(" Q\n"); 0585 0586 $this->_dictionary->touch(); 0587 $this->_dictionary->Contents = $newContentsArray; 0588 0589 $this->_safeGS = true; 0590 } 0591 0592 $this->_dictionary->Contents->items[] = 0593 $this->_objFactory->newStreamObject($this->_contents); 0594 0595 $this->_contents = ''; 0596 } 0597 0598 /** 0599 * Prepare page to be rendered into PDF. 0600 * 0601 * @todo Don't forget to close all current graphics operations (like path drawing) 0602 * 0603 * @param Zend_Pdf_ElementFactory_Interface $objFactory 0604 * @throws Zend_Pdf_Exception 0605 */ 0606 public function render(Zend_Pdf_ElementFactory_Interface $objFactory) 0607 { 0608 $this->flush(); 0609 0610 if ($objFactory === $this->_objFactory) { 0611 // Page is already attached to the document. 0612 return; 0613 } 0614 0615 if ($this->_attached) { 0616 // require_once 'Zend/Pdf/Exception.php'; 0617 throw new Zend_Pdf_Exception('Page is attached to other documen. Use clone $page to get it context free.'); 0618 } else { 0619 $objFactory->attach($this->_objFactory); 0620 } 0621 } 0622 0623 /** 0624 * Extract resources attached to the page 0625 * 0626 * This method is not intended to be used in userland, but helps to optimize some document wide operations 0627 * 0628 * returns array of Zend_Pdf_Element_Dictionary objects 0629 * 0630 * @internal 0631 * @return array 0632 */ 0633 public function extractResources() 0634 { 0635 return $this->_dictionary->Resources; 0636 } 0637 0638 /** 0639 * Extract fonts attached to the page 0640 * 0641 * returns array of Zend_Pdf_Resource_Font_Extracted objects 0642 * 0643 * @return array 0644 * @throws Zend_Pdf_Exception 0645 */ 0646 public function extractFonts() 0647 { 0648 if ($this->_dictionary->Resources->Font === null) { 0649 // Page doesn't have any font attached 0650 // Return empty array 0651 return array(); 0652 } 0653 0654 $fontResources = $this->_dictionary->Resources->Font; 0655 0656 $fontResourcesUnique = array(); 0657 foreach ($fontResources->getKeys() as $fontResourceName) { 0658 $fontDictionary = $fontResources->$fontResourceName; 0659 0660 if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference || 0661 $fontDictionary instanceof Zend_Pdf_Element_Object) ) { 0662 // require_once 'Zend/Pdf/Exception.php'; 0663 throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.'); 0664 } 0665 0666 $fontResourcesUnique[spl_object_hash($fontDictionary->getObject())] = $fontDictionary; 0667 } 0668 0669 $fonts = array(); 0670 // require_once 'Zend/Pdf/Exception.php'; 0671 foreach ($fontResourcesUnique as $resourceId => $fontDictionary) { 0672 try { 0673 // require_once 'Zend/Pdf/Resource/Font/Extracted.php'; 0674 // Try to extract font 0675 $extractedFont = new Zend_Pdf_Resource_Font_Extracted($fontDictionary); 0676 0677 $fonts[$resourceId] = $extractedFont; 0678 } catch (Zend_Pdf_Exception $e) { 0679 if ($e->getMessage() != 'Unsupported font type.') { 0680 throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e); 0681 } 0682 } 0683 } 0684 0685 return $fonts; 0686 } 0687 0688 /** 0689 * Extract font attached to the page by specific font name 0690 * 0691 * $fontName should be specified in UTF-8 encoding 0692 * 0693 * @return Zend_Pdf_Resource_Font_Extracted|null 0694 * @throws Zend_Pdf_Exception 0695 */ 0696 public function extractFont($fontName) 0697 { 0698 if ($this->_dictionary->Resources->Font === null) { 0699 // Page doesn't have any font attached 0700 return null; 0701 } 0702 0703 $fontResources = $this->_dictionary->Resources->Font; 0704 0705 $fontResourcesUnique = array(); 0706 0707 // require_once 'Zend/Pdf/Exception.php'; 0708 foreach ($fontResources->getKeys() as $fontResourceName) { 0709 $fontDictionary = $fontResources->$fontResourceName; 0710 0711 if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference || 0712 $fontDictionary instanceof Zend_Pdf_Element_Object) ) { 0713 // require_once 'Zend/Pdf/Exception.php'; 0714 throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.'); 0715 } 0716 0717 $resourceId = spl_object_hash($fontDictionary->getObject()); 0718 if (isset($fontResourcesUnique[$resourceId])) { 0719 continue; 0720 } else { 0721 // Mark resource as processed 0722 $fontResourcesUnique[$resourceId] = 1; 0723 } 0724 0725 if ($fontDictionary->BaseFont->value != $fontName) { 0726 continue; 0727 } 0728 0729 try { 0730 // Try to extract font 0731 // require_once 'Zend/Pdf/Resource/Font/Extracted.php'; 0732 return new Zend_Pdf_Resource_Font_Extracted($fontDictionary); 0733 } catch (Zend_Pdf_Exception $e) { 0734 if ($e->getMessage() != 'Unsupported font type.') { 0735 throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e); 0736 } 0737 0738 // Continue searhing font with specified name 0739 } 0740 } 0741 0742 return null; 0743 } 0744 0745 /** 0746 * 0747 * @param Zend_Pdf_Annotation $annotation 0748 * @return Zend_Pdf_Page 0749 */ 0750 public function attachAnnotation(Zend_Pdf_Annotation $annotation) 0751 { 0752 $annotationDictionary = $annotation->getResource(); 0753 if (!$annotationDictionary instanceof Zend_Pdf_Element_Object && 0754 !$annotationDictionary instanceof Zend_Pdf_Element_Reference) { 0755 $annotationDictionary = $this->_objFactory->newObject($annotationDictionary); 0756 } 0757 0758 if ($this->_dictionary->Annots === null) { 0759 $this->_dictionary->touch(); 0760 $this->_dictionary->Annots = new Zend_Pdf_Element_Array(); 0761 } else { 0762 $this->_dictionary->Annots->touch(); 0763 } 0764 0765 $this->_dictionary->Annots->items[] = $annotationDictionary; 0766 0767 $annotationDictionary->touch(); 0768 $annotationDictionary->P = $this->_dictionary; 0769 0770 return $this; 0771 } 0772 } 0773