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 }