File indexing completed on 2025-01-19 05:21:22
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 * @subpackage Actions 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** Internally used classes */ 0025 // require_once 'Zend/Pdf/Element.php'; 0026 // require_once 'Zend/Pdf/Element/Array.php'; 0027 // require_once 'Zend/Pdf/Element/Numeric.php'; 0028 // require_once 'Zend/Pdf/Element/String.php'; 0029 0030 0031 /** Zend_Pdf_Outline */ 0032 // require_once 'Zend/Pdf/Outline.php'; 0033 0034 /** 0035 * Traceable PDF outline representation class 0036 * 0037 * Instances of this class trace object update uperations. That allows to avoid outlines PDF tree update 0038 * which should be performed at each document update otherwise. 0039 * 0040 * @package Zend_Pdf 0041 * @subpackage Outlines 0042 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0043 * @license http://framework.zend.com/license/new-bsd New BSD License 0044 */ 0045 class Zend_Pdf_Outline_Loaded extends Zend_Pdf_Outline 0046 { 0047 /** 0048 * Outline dictionary object 0049 * 0050 * @var Zend_Pdf_Element_Dictionary|Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference 0051 */ 0052 protected $_outlineDictionary; 0053 0054 /** 0055 * original array of child outlines 0056 * 0057 * @var array 0058 */ 0059 protected $_originalChildOutlines = array(); 0060 0061 /** 0062 * Get outline title. 0063 * 0064 * @return string 0065 * @throws Zend_Pdf_Exception 0066 */ 0067 public function getTitle() 0068 { 0069 if ($this->_outlineDictionary->Title === null) { 0070 // require_once 'Zend/Pdf/Exception.php'; 0071 throw new Zend_Pdf_Exception('Outline dictionary Title entry is required.'); 0072 } 0073 return $this->_outlineDictionary->Title->value; 0074 } 0075 0076 /** 0077 * Set outline title 0078 * 0079 * @param string $title 0080 * @return Zend_Pdf_Outline 0081 */ 0082 public function setTitle($title) 0083 { 0084 $this->_outlineDictionary->Title->touch(); 0085 $this->_outlineDictionary->Title = new Zend_Pdf_Element_String($title); 0086 return $this; 0087 } 0088 0089 /** 0090 * Sets 'isOpen' outline flag 0091 * 0092 * @param boolean $isOpen 0093 * @return Zend_Pdf_Outline 0094 */ 0095 public function setIsOpen($isOpen) 0096 { 0097 parent::setIsOpen($isOpen); 0098 0099 if ($this->_outlineDictionary->Count === null) { 0100 // Do Nothing. 0101 return this; 0102 } 0103 0104 $childrenCount = $this->_outlineDictionary->Count->value; 0105 $isOpenCurrentState = ($childrenCount > 0); 0106 if ($isOpen != $isOpenCurrentState) { 0107 $this->_outlineDictionary->Count->touch(); 0108 $this->_outlineDictionary->Count->value = ($isOpen? 1 : -1)*abs($childrenCount); 0109 } 0110 0111 return $this; 0112 } 0113 0114 /** 0115 * Returns true if outline item is displayed in italic 0116 * 0117 * @return boolean 0118 */ 0119 public function isItalic() 0120 { 0121 if ($this->_outlineDictionary->F === null) { 0122 return false; 0123 } 0124 return $this->_outlineDictionary->F->value & 1; 0125 } 0126 0127 /** 0128 * Sets 'isItalic' outline flag 0129 * 0130 * @param boolean $isItalic 0131 * @return Zend_Pdf_Outline 0132 */ 0133 public function setIsItalic($isItalic) 0134 { 0135 if ($this->_outlineDictionary->F === null) { 0136 $this->_outlineDictionary->touch(); 0137 $this->_outlineDictionary->F = new Zend_Pdf_Element_Numeric($isItalic? 1 : 0); 0138 } else { 0139 $this->_outlineDictionary->F->touch(); 0140 if ($isItalic) { 0141 $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | 1; 0142 } else { 0143 $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | ~1; 0144 } 0145 } 0146 return $this; 0147 } 0148 0149 /** 0150 * Returns true if outline item is displayed in bold 0151 * 0152 * @return boolean 0153 */ 0154 public function isBold() 0155 { 0156 if ($this->_outlineDictionary->F === null) { 0157 return false; 0158 } 0159 return $this->_outlineDictionary->F->value & 2; 0160 } 0161 0162 /** 0163 * Sets 'isBold' outline flag 0164 * 0165 * @param boolean $isBold 0166 * @return Zend_Pdf_Outline 0167 */ 0168 public function setIsBold($isBold) 0169 { 0170 if ($this->_outlineDictionary->F === null) { 0171 $this->_outlineDictionary->touch(); 0172 $this->_outlineDictionary->F = new Zend_Pdf_Element_Numeric($isBold? 2 : 0); 0173 } else { 0174 $this->_outlineDictionary->F->touch(); 0175 if ($isBold) { 0176 $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | 2; 0177 } else { 0178 $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | ~2; 0179 } 0180 } 0181 return $this; 0182 } 0183 0184 0185 /** 0186 * Get outline text color. 0187 * 0188 * @return Zend_Pdf_Color_Rgb 0189 */ 0190 public function getColor() 0191 { 0192 if ($this->_outlineDictionary->C === null) { 0193 return null; 0194 } 0195 0196 $components = $this->_outlineDictionary->C->items; 0197 0198 // require_once 'Zend/Pdf/Color/Rgb.php'; 0199 return new Zend_Pdf_Color_Rgb($components[0], $components[1], $components[2]); 0200 } 0201 0202 /** 0203 * Set outline text color. 0204 * (null means default color which is black) 0205 * 0206 * @param Zend_Pdf_Color_Rgb $color 0207 * @return Zend_Pdf_Outline 0208 */ 0209 public function setColor(Zend_Pdf_Color_Rgb $color) 0210 { 0211 $this->_outlineDictionary->touch(); 0212 0213 if ($color === null) { 0214 $this->_outlineDictionary->C = null; 0215 } else { 0216 $components = $color->getComponents(); 0217 $colorComponentElements = array(new Zend_Pdf_Element_Numeric($components[0]), 0218 new Zend_Pdf_Element_Numeric($components[1]), 0219 new Zend_Pdf_Element_Numeric($components[2])); 0220 $this->_outlineDictionary->C = new Zend_Pdf_Element_Array($colorComponentElements); 0221 } 0222 0223 return $this; 0224 } 0225 0226 /** 0227 * Get outline target. 0228 * 0229 * @return Zend_Pdf_Target 0230 * @throws Zend_Pdf_Exception 0231 */ 0232 public function getTarget() 0233 { 0234 if ($this->_outlineDictionary->Dest !== null) { 0235 if ($this->_outlineDictionary->A !== null) { 0236 // require_once 'Zend/Pdf/Exception.php'; 0237 throw new Zend_Pdf_Exception('Outline dictionary may contain Dest or A entry, but not both.'); 0238 } 0239 0240 // require_once 'Zend/Pdf/Destination.php'; 0241 return Zend_Pdf_Destination::load($this->_outlineDictionary->Dest); 0242 } else if ($this->_outlineDictionary->A !== null) { 0243 // require_once 'Zend/Pdf/Action.php'; 0244 return Zend_Pdf_Action::load($this->_outlineDictionary->A); 0245 } 0246 0247 return null; 0248 } 0249 0250 /** 0251 * Set outline target. 0252 * Null means no target 0253 * 0254 * @param Zend_Pdf_Target|string $target 0255 * @return Zend_Pdf_Outline 0256 * @throws Zend_Pdf_Exception 0257 */ 0258 public function setTarget($target = null) 0259 { 0260 $this->_outlineDictionary->touch(); 0261 0262 if (is_string($target)) { 0263 // require_once 'Zend/Pdf/Destination/Named.php'; 0264 $target = Zend_Pdf_Destination_Named::create($target); 0265 } 0266 0267 if ($target === null) { 0268 $this->_outlineDictionary->Dest = null; 0269 $this->_outlineDictionary->A = null; 0270 } else if ($target instanceof Zend_Pdf_Destination) { 0271 $this->_outlineDictionary->Dest = $target->getResource(); 0272 $this->_outlineDictionary->A = null; 0273 } else if ($target instanceof Zend_Pdf_Action) { 0274 $this->_outlineDictionary->Dest = null; 0275 $this->_outlineDictionary->A = $target->getResource(); 0276 } else { 0277 // require_once 'Zend/Pdf/Exception.php'; 0278 throw new Zend_Pdf_Exception('Outline target has to be Zend_Pdf_Destination or Zend_Pdf_Action object or string'); 0279 } 0280 0281 return $this; 0282 } 0283 0284 /** 0285 * Set outline options 0286 * 0287 * @param array $options 0288 * @return Zend_Pdf_Actions_Traceable 0289 * @throws Zend_Pdf_Exception 0290 */ 0291 public function setOptions(array $options) 0292 { 0293 parent::setOptions($options); 0294 0295 return $this; 0296 } 0297 0298 0299 0300 /** 0301 * Create PDF outline object using specified dictionary 0302 * 0303 * @internal 0304 * @param Zend_Pdf_Element $dictionary (It's actually Dictionary or Dictionary Object or Reference to a Dictionary Object) 0305 * @param Zend_Pdf_Action $parentAction 0306 * @param SplObjectStorage $processedOutlines List of already processed Outline dictionaries, 0307 * used to avoid cyclic references 0308 * @return Zend_Pdf_Action 0309 * @throws Zend_Pdf_Exception 0310 */ 0311 public function __construct(Zend_Pdf_Element $dictionary, SplObjectStorage $processedDictionaries = null) 0312 { 0313 if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { 0314 // require_once 'Zend/Pdf/Exception.php'; 0315 throw new Zend_Pdf_Exception('$dictionary mast be an indirect dictionary object.'); 0316 } 0317 0318 if ($processedDictionaries === null) { 0319 $processedDictionaries = new SplObjectStorage(); 0320 } 0321 $processedDictionaries->attach($dictionary); 0322 0323 $this->_outlineDictionary = $dictionary; 0324 0325 if ($dictionary->Count !== null) { 0326 if ($dictionary->Count->getType() != Zend_Pdf_Element::TYPE_NUMERIC) { 0327 // require_once 'Zend/Pdf/Exception.php'; 0328 throw new Zend_Pdf_Exception('Outline dictionary Count entry must be a numeric element.'); 0329 } 0330 0331 $childOutlinesCount = $dictionary->Count->value; 0332 if ($childOutlinesCount > 0) { 0333 $this->_open = true; 0334 } 0335 $childOutlinesCount = abs($childOutlinesCount); 0336 0337 $childDictionary = $dictionary->First; 0338 0339 $children = new SplObjectStorage(); 0340 while ($childDictionary !== null) { 0341 // Check children structure for cyclic references 0342 if ($children->contains($childDictionary)) { 0343 // require_once 'Zend/Pdf/Exception.php'; 0344 throw new Zend_Pdf_Exception('Outline childs load error.'); 0345 } 0346 0347 if (!$processedDictionaries->contains($childDictionary)) { 0348 $this->childOutlines[] = new Zend_Pdf_Outline_Loaded($childDictionary, $processedDictionaries); 0349 } 0350 0351 $childDictionary = $childDictionary->Next; 0352 } 0353 0354 $this->_originalChildOutlines = $this->childOutlines; 0355 } 0356 } 0357 0358 /** 0359 * Dump Outline and its child outlines into PDF structures 0360 * 0361 * Returns dictionary indirect object or reference 0362 * 0363 * @internal 0364 * @param Zend_Pdf_ElementFactory $factory object factory for newly created indirect objects 0365 * @param boolean $updateNavigation Update navigation flag 0366 * @param Zend_Pdf_Element $parent Parent outline dictionary reference 0367 * @param Zend_Pdf_Element $prev Previous outline dictionary reference 0368 * @param SplObjectStorage $processedOutlines List of already processed outlines 0369 * @return Zend_Pdf_Element 0370 * @throws Zend_Pdf_Exception 0371 */ 0372 public function dumpOutline(Zend_Pdf_ElementFactory_Interface $factory, 0373 $updateNavigation, 0374 Zend_Pdf_Element $parent, 0375 Zend_Pdf_Element $prev = null, 0376 SplObjectStorage $processedOutlines = null) 0377 { 0378 if ($processedOutlines === null) { 0379 $processedOutlines = new SplObjectStorage(); 0380 } 0381 $processedOutlines->attach($this); 0382 0383 if ($updateNavigation) { 0384 $this->_outlineDictionary->touch(); 0385 0386 $this->_outlineDictionary->Parent = $parent; 0387 $this->_outlineDictionary->Prev = $prev; 0388 $this->_outlineDictionary->Next = null; 0389 } 0390 0391 $updateChildNavigation = false; 0392 if (count($this->_originalChildOutlines) != count($this->childOutlines)) { 0393 // If original and current children arrays have different size then children list was updated 0394 $updateChildNavigation = true; 0395 } else if ( !(array_keys($this->_originalChildOutlines) === array_keys($this->childOutlines)) ) { 0396 // If original and current children arrays have different keys (with a glance to an order) then children list was updated 0397 $updateChildNavigation = true; 0398 } else { 0399 foreach ($this->childOutlines as $key => $childOutline) { 0400 if ($this->_originalChildOutlines[$key] !== $childOutline) { 0401 $updateChildNavigation = true; 0402 break; 0403 } 0404 } 0405 } 0406 0407 $lastChild = null; 0408 if ($updateChildNavigation) { 0409 $this->_outlineDictionary->touch(); 0410 $this->_outlineDictionary->First = null; 0411 0412 foreach ($this->childOutlines as $childOutline) { 0413 if ($processedOutlines->contains($childOutline)) { 0414 // require_once 'Zend/Pdf/Exception.php'; 0415 throw new Zend_Pdf_Exception('Outlines cyclyc reference is detected.'); 0416 } 0417 0418 if ($lastChild === null) { 0419 // First pass. Update Outlines dictionary First entry using corresponding value 0420 $lastChild = $childOutline->dumpOutline($factory, $updateChildNavigation, $this->_outlineDictionary, null, $processedOutlines); 0421 $this->_outlineDictionary->First = $lastChild; 0422 } else { 0423 // Update previous outline dictionary Next entry (Prev is updated within dumpOutline() method) 0424 $childOutlineDictionary = $childOutline->dumpOutline($factory, $updateChildNavigation, $this->_outlineDictionary, $lastChild, $processedOutlines); 0425 $lastChild->Next = $childOutlineDictionary; 0426 $lastChild = $childOutlineDictionary; 0427 } 0428 } 0429 0430 $this->_outlineDictionary->Last = $lastChild; 0431 0432 if (count($this->childOutlines) != 0) { 0433 $this->_outlineDictionary->Count = new Zend_Pdf_Element_Numeric(($this->isOpen()? 1 : -1)*count($this->childOutlines)); 0434 } else { 0435 $this->_outlineDictionary->Count = null; 0436 } 0437 } else { 0438 foreach ($this->childOutlines as $childOutline) { 0439 if ($processedOutlines->contains($childOutline)) { 0440 // require_once 'Zend/Pdf/Exception.php'; 0441 throw new Zend_Pdf_Exception('Outlines cyclyc reference is detected.'); 0442 } 0443 $lastChild = $childOutline->dumpOutline($factory, $updateChildNavigation, $this->_outlineDictionary, $lastChild, $processedOutlines); 0444 } 0445 } 0446 0447 return $this->_outlineDictionary; 0448 } 0449 0450 public function dump($level = 0) 0451 { 0452 printf(":%3d:%s:%s:%s%s :\n", count($this->childOutlines),$this->isItalic()? 'i':' ', $this->isBold()? 'b':' ', str_pad('', 4*$level), $this->getTitle()); 0453 0454 if ($this->isOpen() || true) { 0455 foreach ($this->childOutlines as $child) { 0456 $child->dump($level + 1); 0457 } 0458 } 0459 } 0460 }