You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

773 lines
27 KiB

11 years ago
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Pdf
  17. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Page.php 24593 2012-01-05 20:35:02Z matthew $
  20. */
  21. /** Internally used classes */
  22. // require_once 'Zend/Pdf/Element.php';
  23. // require_once 'Zend/Pdf/Element/Array.php';
  24. // require_once 'Zend/Pdf/Element/String/Binary.php';
  25. // require_once 'Zend/Pdf/Element/Boolean.php';
  26. // require_once 'Zend/Pdf/Element/Dictionary.php';
  27. // require_once 'Zend/Pdf/Element/Name.php';
  28. // require_once 'Zend/Pdf/Element/Null.php';
  29. // require_once 'Zend/Pdf/Element/Numeric.php';
  30. // require_once 'Zend/Pdf/Element/String.php';
  31. // require_once 'Zend/Pdf/Resource/Unified.php';
  32. // require_once 'Zend/Pdf/Canvas/Abstract.php';
  33. /**
  34. * PDF Page
  35. *
  36. * @package Zend_Pdf
  37. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  38. * @license http://framework.zend.com/license/new-bsd New BSD License
  39. */
  40. class Zend_Pdf_Page extends Zend_Pdf_Canvas_Abstract
  41. {
  42. /**** Class Constants ****/
  43. /* Page Sizes */
  44. /**
  45. * Size representing an A4 page in portrait (tall) orientation.
  46. */
  47. const SIZE_A4 = '595:842:';
  48. /**
  49. * Size representing an A4 page in landscape (wide) orientation.
  50. */
  51. const SIZE_A4_LANDSCAPE = '842:595:';
  52. /**
  53. * Size representing a US Letter page in portrait (tall) orientation.
  54. */
  55. const SIZE_LETTER = '612:792:';
  56. /**
  57. * Size representing a US Letter page in landscape (wide) orientation.
  58. */
  59. const SIZE_LETTER_LANDSCAPE = '792:612:';
  60. /* Shape Drawing */
  61. /**
  62. * Stroke the path only. Do not fill.
  63. */
  64. const SHAPE_DRAW_STROKE = 0;
  65. /**
  66. * Fill the path only. Do not stroke.
  67. */
  68. const SHAPE_DRAW_FILL = 1;
  69. /**
  70. * Fill and stroke the path.
  71. */
  72. const SHAPE_DRAW_FILL_AND_STROKE = 2;
  73. /* Shape Filling Methods */
  74. /**
  75. * Fill the path using the non-zero winding rule.
  76. */
  77. const FILL_METHOD_NON_ZERO_WINDING = 0;
  78. /**
  79. * Fill the path using the even-odd rule.
  80. */
  81. const FILL_METHOD_EVEN_ODD = 1;
  82. /* Line Dash Types */
  83. /**
  84. * Solid line dash.
  85. */
  86. const LINE_DASHING_SOLID = 0;
  87. /**
  88. * Page dictionary (refers to an inderect Zend_Pdf_Element_Dictionary object).
  89. *
  90. * @var Zend_Pdf_Element_Reference|Zend_Pdf_Element_Object
  91. */
  92. protected $_dictionary;
  93. /**
  94. * PDF objects factory.
  95. *
  96. * @var Zend_Pdf_ElementFactory_Interface
  97. */
  98. protected $_objFactory = null;
  99. /**
  100. * Flag which signals, that page is created separately from any PDF document or
  101. * attached to anyone.
  102. *
  103. * @var boolean
  104. */
  105. protected $_attached;
  106. /**
  107. * Safe Graphics State semafore
  108. *
  109. * If it's false, than we can't be sure Graphics State is restored withing
  110. * context of previous contents stream (ex. drawing coordinate system may be rotated).
  111. * We should encompass existing content with save/restore GS operators
  112. *
  113. * @var boolean
  114. */
  115. protected $_safeGS;
  116. /**
  117. * Object constructor.
  118. * Constructor signatures:
  119. *
  120. * 1. Load PDF page from a parsed PDF file.
  121. * Object factory is created by PDF parser.
  122. * ---------------------------------------------------------
  123. * new Zend_Pdf_Page(Zend_Pdf_Element_Dictionary $pageDict,
  124. * Zend_Pdf_ElementFactory_Interface $factory);
  125. * ---------------------------------------------------------
  126. *
  127. * 2. Make a copy of the PDF page.
  128. * New page is created in the same context as source page. Object factory is shared.
  129. * Thus it will be attached to the document, but need to be placed into Zend_Pdf::$pages array
  130. * to be included into output.
  131. * ---------------------------------------------------------
  132. * new Zend_Pdf_Page(Zend_Pdf_Page $page);
  133. * ---------------------------------------------------------
  134. *
  135. * 3. Create new page with a specified pagesize.
  136. * If $factory is null then it will be created and page must be attached to the document to be
  137. * included into output.
  138. * ---------------------------------------------------------
  139. * new Zend_Pdf_Page(string $pagesize, Zend_Pdf_ElementFactory_Interface $factory = null);
  140. * ---------------------------------------------------------
  141. *
  142. * 4. Create new page with a specified pagesize (in default user space units).
  143. * If $factory is null then it will be created and page must be attached to the document to be
  144. * included into output.
  145. * ---------------------------------------------------------
  146. * new Zend_Pdf_Page(numeric $width, numeric $height, Zend_Pdf_ElementFactory_Interface $factory = null);
  147. * ---------------------------------------------------------
  148. *
  149. *
  150. * @param mixed $param1
  151. * @param mixed $param2
  152. * @param mixed $param3
  153. * @throws Zend_Pdf_Exception
  154. */
  155. public function __construct($param1, $param2 = null, $param3 = null)
  156. {
  157. if (($param1 instanceof Zend_Pdf_Element_Reference ||
  158. $param1 instanceof Zend_Pdf_Element_Object
  159. ) &&
  160. $param2 instanceof Zend_Pdf_ElementFactory_Interface &&
  161. $param3 === null
  162. ) {
  163. switch ($param1->getType()) {
  164. case Zend_Pdf_Element::TYPE_DICTIONARY:
  165. $this->_dictionary = $param1;
  166. $this->_objFactory = $param2;
  167. $this->_attached = true;
  168. $this->_safeGS = false;
  169. return;
  170. break;
  171. case Zend_Pdf_Element::TYPE_NULL:
  172. $this->_objFactory = $param2;
  173. $pageWidth = $pageHeight = 0;
  174. break;
  175. default:
  176. // require_once 'Zend/Pdf/Exception.php';
  177. throw new Zend_Pdf_Exception('Unrecognized object type.');
  178. break;
  179. }
  180. } else if ($param1 instanceof Zend_Pdf_Page && $param2 === null && $param3 === null) {
  181. // Duplicate existing page.
  182. // Let already existing content and resources to be shared between pages
  183. // We don't give existing content modification functionality, so we don't need "deep copy"
  184. $this->_objFactory = $param1->_objFactory;
  185. $this->_attached = &$param1->_attached;
  186. $this->_safeGS = false;
  187. $this->_dictionary = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
  188. foreach ($param1->_dictionary->getKeys() as $key) {
  189. if ($key == 'Contents') {
  190. // Clone Contents property
  191. $this->_dictionary->Contents = new Zend_Pdf_Element_Array();
  192. if ($param1->_dictionary->Contents->getType() != Zend_Pdf_Element::TYPE_ARRAY) {
  193. // Prepare array of content streams and add existing stream
  194. $this->_dictionary->Contents->items[] = $param1->_dictionary->Contents;
  195. } else {
  196. // Clone array of the content streams
  197. foreach ($param1->_dictionary->Contents->items as $srcContentStream) {
  198. $this->_dictionary->Contents->items[] = $srcContentStream;
  199. }
  200. }
  201. } else {
  202. $this->_dictionary->$key = $param1->_dictionary->$key;
  203. }
  204. }
  205. return;
  206. } else if (is_string($param1) &&
  207. ($param2 === null || $param2 instanceof Zend_Pdf_ElementFactory_Interface) &&
  208. $param3 === null) {
  209. if ($param2 !== null) {
  210. $this->_objFactory = $param2;
  211. } else {
  212. // require_once 'Zend/Pdf/ElementFactory.php';
  213. $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1);
  214. }
  215. $this->_attached = false;
  216. $this->_safeGS = true; /** New page created. That's users App responsibility to track GS changes */
  217. switch (strtolower($param1)) {
  218. case 'a4':
  219. $param1 = Zend_Pdf_Page::SIZE_A4;
  220. break;
  221. case 'a4-landscape':
  222. $param1 = Zend_Pdf_Page::SIZE_A4_LANDSCAPE;
  223. break;
  224. case 'letter':
  225. $param1 = Zend_Pdf_Page::SIZE_LETTER;
  226. break;
  227. case 'letter-landscape':
  228. $param1 = Zend_Pdf_Page::SIZE_LETTER_LANDSCAPE;
  229. break;
  230. default:
  231. // should be in "x:y" or "x:y:" form
  232. }
  233. $pageDim = explode(':', $param1);
  234. if(count($pageDim) == 2 || count($pageDim) == 3) {
  235. $pageWidth = $pageDim[0];
  236. $pageHeight = $pageDim[1];
  237. } else {
  238. /**
  239. * @todo support of user defined pagesize notations, like:
  240. * "210x297mm", "595x842", "8.5x11in", "612x792"
  241. */
  242. // require_once 'Zend/Pdf/Exception.php';
  243. throw new Zend_Pdf_Exception('Wrong pagesize notation.');
  244. }
  245. /**
  246. * @todo support of pagesize recalculation to "default user space units"
  247. */
  248. } else if (is_numeric($param1) && is_numeric($param2) &&
  249. ($param3 === null || $param3 instanceof Zend_Pdf_ElementFactory_Interface)) {
  250. if ($param3 !== null) {
  251. $this->_objFactory = $param3;
  252. } else {
  253. // require_once 'Zend/Pdf/ElementFactory.php';
  254. $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1);
  255. }
  256. $this->_attached = false;
  257. $this->_safeGS = true; /** New page created. That's users App responsibility to track GS changes */
  258. $pageWidth = $param1;
  259. $pageHeight = $param2;
  260. } else {
  261. // require_once 'Zend/Pdf/Exception.php';
  262. throw new Zend_Pdf_Exception('Unrecognized method signature, wrong number of arguments or wrong argument types.');
  263. }
  264. $this->_dictionary = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary());
  265. $this->_dictionary->Type = new Zend_Pdf_Element_Name('Page');
  266. // require_once 'Zend/Pdf.php';
  267. $this->_dictionary->LastModified = new Zend_Pdf_Element_String(Zend_Pdf::pdfDate());
  268. $this->_dictionary->Resources = new Zend_Pdf_Element_Dictionary();
  269. $this->_dictionary->MediaBox = new Zend_Pdf_Element_Array();
  270. $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0);
  271. $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0);
  272. $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageWidth);
  273. $this->_dictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageHeight);
  274. $this->_dictionary->Contents = new Zend_Pdf_Element_Array();
  275. }
  276. /**
  277. * Attach resource to the canvas
  278. *
  279. * Method returns a name of the resource which can be used
  280. * as a resource reference within drawing instructions stream
  281. * Allowed types: 'ExtGState', 'ColorSpace', 'Pattern', 'Shading',
  282. * 'XObject', 'Font', 'Properties'
  283. *
  284. * @param string $type
  285. * @param Zend_Pdf_Resource $resource
  286. * @return string
  287. */
  288. protected function _attachResource($type, Zend_Pdf_Resource $resource)
  289. {
  290. // Check that Resources dictionary contains appropriate resource set
  291. if ($this->_dictionary->Resources->$type === null) {
  292. $this->_dictionary->Resources->touch();
  293. $this->_dictionary->Resources->$type = new Zend_Pdf_Element_Dictionary();
  294. } else {
  295. $this->_dictionary->Resources->$type->touch();
  296. }
  297. // Check, that resource is already attached to resource set.
  298. $resObject = $resource->getResource();
  299. foreach ($this->_dictionary->Resources->$type->getKeys() as $ResID) {
  300. if ($this->_dictionary->Resources->$type->$ResID === $resObject) {
  301. return $ResID;
  302. }
  303. }
  304. $idCounter = 1;
  305. do {
  306. $newResName = $type[0] . $idCounter++;
  307. } while ($this->_dictionary->Resources->$type->$newResName !== null);
  308. $this->_dictionary->Resources->$type->$newResName = $resObject;
  309. $this->_objFactory->attach($resource->getFactory());
  310. return $newResName;
  311. }
  312. /**
  313. * Add procedureSet to the Page description
  314. *
  315. * @param string $procSetName
  316. */
  317. protected function _addProcSet($procSetName)
  318. {
  319. // Check that Resources dictionary contains ProcSet entry
  320. if ($this->_dictionary->Resources->ProcSet === null) {
  321. $this->_dictionary->Resources->touch();
  322. $this->_dictionary->Resources->ProcSet = new Zend_Pdf_Element_Array();
  323. } else {
  324. $this->_dictionary->Resources->ProcSet->touch();
  325. }
  326. foreach ($this->_dictionary->Resources->ProcSet->items as $procSetEntry) {
  327. if ($procSetEntry->value == $procSetName) {
  328. // Procset is already included into a ProcSet array
  329. return;
  330. }
  331. }
  332. $this->_dictionary->Resources->ProcSet->items[] = new Zend_Pdf_Element_Name($procSetName);
  333. }
  334. /**
  335. * Returns dictionaries of used resources.
  336. *
  337. * Used for canvas implementations interoperability
  338. *
  339. * Structure of the returned array:
  340. * array(
  341. * <resTypeName> => array(
  342. * <resName> => <Zend_Pdf_Resource object>,
  343. * <resName> => <Zend_Pdf_Resource object>,
  344. * <resName> => <Zend_Pdf_Resource object>,
  345. * ...
  346. * ),
  347. * <resTypeName> => array(
  348. * <resName> => <Zend_Pdf_Resource object>,
  349. * <resName> => <Zend_Pdf_Resource object>,
  350. * <resName> => <Zend_Pdf_Resource object>,
  351. * ...
  352. * ),
  353. * ...
  354. * 'ProcSet' => array()
  355. * )
  356. *
  357. * where ProcSet array is a list of used procedure sets names (strings).
  358. * Allowed procedure set names: 'PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'
  359. *
  360. * @internal
  361. * @return array
  362. */
  363. public function getResources()
  364. {
  365. $resources = array();
  366. $resDictionary = $this->_dictionary->Resources;
  367. foreach ($resDictionary->getKeys() as $resType) {
  368. $resources[$resType] = array();
  369. if ($resType == 'ProcSet') {
  370. foreach ($resDictionary->ProcSet->items as $procSetEntry) {
  371. $resources[$resType][] = $procSetEntry->value;
  372. }
  373. } else {
  374. $resMap = $resDictionary->$resType;
  375. foreach ($resMap->getKeys() as $resId) {
  376. $resources[$resType][$resId] =new Zend_Pdf_Resource_Unified($resMap->$resId);
  377. }
  378. }
  379. }
  380. return $resources;
  381. }
  382. /**
  383. * Get drawing instructions stream
  384. *
  385. * It has to be returned as a PDF stream object to make it reusable.
  386. *
  387. * @internal
  388. * @returns Zend_Pdf_Resource_ContentStream
  389. */
  390. public function getContents()
  391. {
  392. /** @todo implementation */
  393. }
  394. /**
  395. * Return the height of this page in points.
  396. *
  397. * @return float
  398. */
  399. public function getHeight()
  400. {
  401. return $this->_dictionary->MediaBox->items[3]->value -
  402. $this->_dictionary->MediaBox->items[1]->value;
  403. }
  404. /**
  405. * Return the width of this page in points.
  406. *
  407. * @return float
  408. */
  409. public function getWidth()
  410. {
  411. return $this->_dictionary->MediaBox->items[2]->value -
  412. $this->_dictionary->MediaBox->items[0]->value;
  413. }
  414. /**
  415. * Clone page, extract it and dependent objects from the current document,
  416. * so it can be used within other docs.
  417. */
  418. public function __clone()
  419. {
  420. $factory = Zend_Pdf_ElementFactory::createFactory(1);
  421. $processed = array();
  422. // Clone dictionary object.
  423. // Do it explicitly to prevent sharing page attributes between different
  424. // results of clonePage() operation (other resources are still shared)
  425. $dictionary = new Zend_Pdf_Element_Dictionary();
  426. foreach ($this->_dictionary->getKeys() as $key) {
  427. $dictionary->$key = $this->_dictionary->$key->makeClone($factory->getFactory(),
  428. $processed,
  429. Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES);
  430. }
  431. $this->_dictionary = $factory->newObject($dictionary);
  432. $this->_objFactory = $factory;
  433. $this->_attached = false;
  434. $this->_style = null;
  435. $this->_font = null;
  436. }
  437. /**
  438. * Clone page, extract it and dependent objects from the current document,
  439. * so it can be used within other docs.
  440. *
  441. * @internal
  442. * @param Zend_Pdf_ElementFactory_Interface $factory
  443. * @param array $processed
  444. * @return Zend_Pdf_Page
  445. */
  446. public function clonePage($factory, &$processed)
  447. {
  448. // Clone dictionary object.
  449. // Do it explicitly to prevent sharing page attributes between different
  450. // results of clonePage() operation (other resources are still shared)
  451. $dictionary = new Zend_Pdf_Element_Dictionary();
  452. foreach ($this->_dictionary->getKeys() as $key) {
  453. $dictionary->$key = $this->_dictionary->$key->makeClone($factory->getFactory(),
  454. $processed,
  455. Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES);
  456. }
  457. $clonedPage = new Zend_Pdf_Page($factory->newObject($dictionary), $factory);
  458. $clonedPage->_attached = false;
  459. return $clonedPage;
  460. }
  461. /**
  462. * Retrive PDF file reference to the page
  463. *
  464. * @internal
  465. * @return Zend_Pdf_Element_Dictionary
  466. */
  467. public function getPageDictionary()
  468. {
  469. return $this->_dictionary;
  470. }
  471. /**
  472. * Dump current drawing instructions into the content stream.
  473. *
  474. * @todo Don't forget to close all current graphics operations (like path drawing)
  475. *
  476. * @throws Zend_Pdf_Exception
  477. */
  478. public function flush()
  479. {
  480. if ($this->_saveCount != 0) {
  481. // require_once 'Zend/Pdf/Exception.php';
  482. throw new Zend_Pdf_Exception('Saved graphics state is not restored');
  483. }
  484. if ($this->_contents == '') {
  485. return;
  486. }
  487. if ($this->_dictionary->Contents->getType() != Zend_Pdf_Element::TYPE_ARRAY) {
  488. /**
  489. * It's a stream object.
  490. * Prepare Contents page attribute for update.
  491. */
  492. $this->_dictionary->touch();
  493. $currentPageContents = $this->_dictionary->Contents;
  494. $this->_dictionary->Contents = new Zend_Pdf_Element_Array();
  495. $this->_dictionary->Contents->items[] = $currentPageContents;
  496. } else {
  497. $this->_dictionary->Contents->touch();
  498. }
  499. if ((!$this->_safeGS) && (count($this->_dictionary->Contents->items) != 0)) {
  500. /**
  501. * Page already has some content which is not treated as safe.
  502. *
  503. * Add save/restore GS operators
  504. */
  505. $this->_addProcSet('PDF');
  506. $newContentsArray = new Zend_Pdf_Element_Array();
  507. $newContentsArray->items[] = $this->_objFactory->newStreamObject(" q\n");
  508. foreach ($this->_dictionary->Contents->items as $contentStream) {
  509. $newContentsArray->items[] = $contentStream;
  510. }
  511. $newContentsArray->items[] = $this->_objFactory->newStreamObject(" Q\n");
  512. $this->_dictionary->touch();
  513. $this->_dictionary->Contents = $newContentsArray;
  514. $this->_safeGS = true;
  515. }
  516. $this->_dictionary->Contents->items[] =
  517. $this->_objFactory->newStreamObject($this->_contents);
  518. $this->_contents = '';
  519. }
  520. /**
  521. * Prepare page to be rendered into PDF.
  522. *
  523. * @todo Don't forget to close all current graphics operations (like path drawing)
  524. *
  525. * @param Zend_Pdf_ElementFactory_Interface $objFactory
  526. * @throws Zend_Pdf_Exception
  527. */
  528. public function render(Zend_Pdf_ElementFactory_Interface $objFactory)
  529. {
  530. $this->flush();
  531. if ($objFactory === $this->_objFactory) {
  532. // Page is already attached to the document.
  533. return;
  534. }
  535. if ($this->_attached) {
  536. // require_once 'Zend/Pdf/Exception.php';
  537. throw new Zend_Pdf_Exception('Page is attached to other documen. Use clone $page to get it context free.');
  538. } else {
  539. $objFactory->attach($this->_objFactory);
  540. }
  541. }
  542. /**
  543. * Extract resources attached to the page
  544. *
  545. * This method is not intended to be used in userland, but helps to optimize some document wide operations
  546. *
  547. * returns array of Zend_Pdf_Element_Dictionary objects
  548. *
  549. * @internal
  550. * @return array
  551. */
  552. public function extractResources()
  553. {
  554. return $this->_dictionary->Resources;
  555. }
  556. /**
  557. * Extract fonts attached to the page
  558. *
  559. * returns array of Zend_Pdf_Resource_Font_Extracted objects
  560. *
  561. * @return array
  562. * @throws Zend_Pdf_Exception
  563. */
  564. public function extractFonts()
  565. {
  566. if ($this->_dictionary->Resources->Font === null) {
  567. // Page doesn't have any font attached
  568. // Return empty array
  569. return array();
  570. }
  571. $fontResources = $this->_dictionary->Resources->Font;
  572. $fontResourcesUnique = array();
  573. foreach ($fontResources->getKeys() as $fontResourceName) {
  574. $fontDictionary = $fontResources->$fontResourceName;
  575. if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference ||
  576. $fontDictionary instanceof Zend_Pdf_Element_Object) ) {
  577. // require_once 'Zend/Pdf/Exception.php';
  578. throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.');
  579. }
  580. $fontResourcesUnique[spl_object_hash($fontDictionary->getObject())] = $fontDictionary;
  581. }
  582. $fonts = array();
  583. // require_once 'Zend/Pdf/Exception.php';
  584. foreach ($fontResourcesUnique as $resourceId => $fontDictionary) {
  585. try {
  586. // require_once 'Zend/Pdf/Resource/Font/Extracted.php';
  587. // Try to extract font
  588. $extractedFont = new Zend_Pdf_Resource_Font_Extracted($fontDictionary);
  589. $fonts[$resourceId] = $extractedFont;
  590. } catch (Zend_Pdf_Exception $e) {
  591. if ($e->getMessage() != 'Unsupported font type.') {
  592. throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e);
  593. }
  594. }
  595. }
  596. return $fonts;
  597. }
  598. /**
  599. * Extract font attached to the page by specific font name
  600. *
  601. * $fontName should be specified in UTF-8 encoding
  602. *
  603. * @return Zend_Pdf_Resource_Font_Extracted|null
  604. * @throws Zend_Pdf_Exception
  605. */
  606. public function extractFont($fontName)
  607. {
  608. if ($this->_dictionary->Resources->Font === null) {
  609. // Page doesn't have any font attached
  610. return null;
  611. }
  612. $fontResources = $this->_dictionary->Resources->Font;
  613. $fontResourcesUnique = array();
  614. // require_once 'Zend/Pdf/Exception.php';
  615. foreach ($fontResources->getKeys() as $fontResourceName) {
  616. $fontDictionary = $fontResources->$fontResourceName;
  617. if (! ($fontDictionary instanceof Zend_Pdf_Element_Reference ||
  618. $fontDictionary instanceof Zend_Pdf_Element_Object) ) {
  619. // require_once 'Zend/Pdf/Exception.php';
  620. throw new Zend_Pdf_Exception('Font dictionary has to be an indirect object or object reference.');
  621. }
  622. $resourceId = spl_object_hash($fontDictionary->getObject());
  623. if (isset($fontResourcesUnique[$resourceId])) {
  624. continue;
  625. } else {
  626. // Mark resource as processed
  627. $fontResourcesUnique[$resourceId] = 1;
  628. }
  629. if ($fontDictionary->BaseFont->value != $fontName) {
  630. continue;
  631. }
  632. try {
  633. // Try to extract font
  634. // require_once 'Zend/Pdf/Resource/Font/Extracted.php';
  635. return new Zend_Pdf_Resource_Font_Extracted($fontDictionary);
  636. } catch (Zend_Pdf_Exception $e) {
  637. if ($e->getMessage() != 'Unsupported font type.') {
  638. throw new Zend_Pdf_Exception($e->getMessage(), $e->getCode(), $e);
  639. }
  640. // Continue searhing font with specified name
  641. }
  642. }
  643. return null;
  644. }
  645. /**
  646. *
  647. * @param Zend_Pdf_Annotation $annotation
  648. * @return Zend_Pdf_Page
  649. */
  650. public function attachAnnotation(Zend_Pdf_Annotation $annotation)
  651. {
  652. $annotationDictionary = $annotation->getResource();
  653. if (!$annotationDictionary instanceof Zend_Pdf_Element_Object &&
  654. !$annotationDictionary instanceof Zend_Pdf_Element_Reference) {
  655. $annotationDictionary = $this->_objFactory->newObject($annotationDictionary);
  656. }
  657. if ($this->_dictionary->Annots === null) {
  658. $this->_dictionary->touch();
  659. $this->_dictionary->Annots = new Zend_Pdf_Element_Array();
  660. } else {
  661. $this->_dictionary->Annots->touch();
  662. }
  663. $this->_dictionary->Annots->items[] = $annotationDictionary;
  664. $annotationDictionary->touch();
  665. $annotationDictionary->P = $this->_dictionary;
  666. return $this;
  667. }
  668. }