web/lib/Zend/Pdf/Element/Object/Stream.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  * @version    $Id: Stream.php 22909 2010-08-27 19:57:48Z alexander $
       
    20  */
       
    21 
       
    22 
       
    23 /** Internally used classes */
       
    24 require_once 'Zend/Pdf/Element/Stream.php';
       
    25 require_once 'Zend/Pdf/Element/Dictionary.php';
       
    26 require_once 'Zend/Pdf/Element/Numeric.php';
       
    27 
       
    28 
       
    29 /** Zend_Pdf_Element_Object */
       
    30 require_once 'Zend/Pdf/Element/Object.php';
       
    31 
       
    32 /**
       
    33  * PDF file 'stream object' element implementation
       
    34  *
       
    35  * @category   Zend
       
    36  * @package    Zend_Pdf
       
    37  * @copyright  Copyright (c) 2005-2010 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_Element_Object_Stream extends Zend_Pdf_Element_Object
       
    41 {
       
    42     /**
       
    43      * StreamObject dictionary
       
    44      * Required enries:
       
    45      * Length
       
    46      *
       
    47      * @var Zend_Pdf_Element_Dictionary
       
    48      */
       
    49     private $_dictionary;
       
    50 
       
    51     /**
       
    52      * Flag which signals, that stream is decoded
       
    53      *
       
    54      * @var boolean
       
    55      */
       
    56     private $_streamDecoded;
       
    57 
       
    58     /**
       
    59      * Stored original stream object dictionary.
       
    60      * Used to decode stream at access time.
       
    61      *
       
    62      * The only properties affecting decoding are sored here.
       
    63      *
       
    64      * @var array|null
       
    65      */
       
    66     private $_initialDictionaryData = null;
       
    67 
       
    68     /**
       
    69      * Object constructor
       
    70      *
       
    71      * @param mixed $val
       
    72      * @param integer $objNum
       
    73      * @param integer $genNum
       
    74      * @param Zend_Pdf_ElementFactory $factory
       
    75      * @param Zend_Pdf_Element_Dictionary|null $dictionary
       
    76      * @throws Zend_Pdf_Exception
       
    77      */
       
    78     public function __construct($val, $objNum, $genNum, Zend_Pdf_ElementFactory $factory, $dictionary = null)
       
    79     {
       
    80         parent::__construct(new Zend_Pdf_Element_Stream($val), $objNum, $genNum, $factory);
       
    81 
       
    82         if ($dictionary === null) {
       
    83             $this->_dictionary    = new Zend_Pdf_Element_Dictionary();
       
    84             $this->_dictionary->Length = new Zend_Pdf_Element_Numeric(strlen( $val ));
       
    85             $this->_streamDecoded = true;
       
    86         } else {
       
    87             $this->_dictionary    = $dictionary;
       
    88             $this->_streamDecoded = false;
       
    89         }
       
    90     }
       
    91 
       
    92 
       
    93     /**
       
    94      * Extract dictionary data which are used to store information and to normalize filters
       
    95      * information before defiltering.
       
    96      *
       
    97      * @return array
       
    98      */
       
    99     private function _extractDictionaryData()
       
   100     {
       
   101         $dictionaryArray = array();
       
   102 
       
   103         $dictionaryArray['Filter']      = array();
       
   104         $dictionaryArray['DecodeParms'] = array();
       
   105         if ($this->_dictionary->Filter === null) {
       
   106             // Do nothing.
       
   107         } else if ($this->_dictionary->Filter->getType() == Zend_Pdf_Element::TYPE_ARRAY) {
       
   108             foreach ($this->_dictionary->Filter->items as $id => $filter) {
       
   109                 $dictionaryArray['Filter'][$id]      = $filter->value;
       
   110                 $dictionaryArray['DecodeParms'][$id] = array();
       
   111 
       
   112                 if ($this->_dictionary->DecodeParms !== null ) {
       
   113                     if ($this->_dictionary->DecodeParms->items[$id] !== null &&
       
   114                         $this->_dictionary->DecodeParms->items[$id]->value !== null ) {
       
   115                         foreach ($this->_dictionary->DecodeParms->items[$id]->getKeys() as $paramKey) {
       
   116                             $dictionaryArray['DecodeParms'][$id][$paramKey] =
       
   117                                   $this->_dictionary->DecodeParms->items[$id]->$paramKey->value;
       
   118                         }
       
   119                     }
       
   120                 }
       
   121             }
       
   122         } else if ($this->_dictionary->Filter->getType() != Zend_Pdf_Element::TYPE_NULL) {
       
   123             $dictionaryArray['Filter'][0]      = $this->_dictionary->Filter->value;
       
   124             $dictionaryArray['DecodeParms'][0] = array();
       
   125             if ($this->_dictionary->DecodeParms !== null ) {
       
   126                 foreach ($this->_dictionary->DecodeParms->getKeys() as $paramKey) {
       
   127                     $dictionaryArray['DecodeParms'][0][$paramKey] =
       
   128                           $this->_dictionary->DecodeParms->$paramKey->value;
       
   129                 }
       
   130             }
       
   131         }
       
   132 
       
   133         if ($this->_dictionary->F !== null) {
       
   134             $dictionaryArray['F'] = $this->_dictionary->F->value;
       
   135         }
       
   136 
       
   137         $dictionaryArray['FFilter']      = array();
       
   138         $dictionaryArray['FDecodeParms'] = array();
       
   139         if ($this->_dictionary->FFilter === null) {
       
   140             // Do nothing.
       
   141         } else if ($this->_dictionary->FFilter->getType() == Zend_Pdf_Element::TYPE_ARRAY) {
       
   142             foreach ($this->_dictionary->FFilter->items as $id => $filter) {
       
   143                 $dictionaryArray['FFilter'][$id]      = $filter->value;
       
   144                 $dictionaryArray['FDecodeParms'][$id] = array();
       
   145 
       
   146                 if ($this->_dictionary->FDecodeParms !== null ) {
       
   147                     if ($this->_dictionary->FDecodeParms->items[$id] !== null &&
       
   148                         $this->_dictionary->FDecodeParms->items[$id]->value !== null) {
       
   149                         foreach ($this->_dictionary->FDecodeParms->items[$id]->getKeys() as $paramKey) {
       
   150                             $dictionaryArray['FDecodeParms'][$id][$paramKey] =
       
   151                                   $this->_dictionary->FDecodeParms->items[$id]->items[$paramKey]->value;
       
   152                         }
       
   153                     }
       
   154                 }
       
   155             }
       
   156         } else {
       
   157             $dictionaryArray['FFilter'][0]      = $this->_dictionary->FFilter->value;
       
   158             $dictionaryArray['FDecodeParms'][0] = array();
       
   159             if ($this->_dictionary->FDecodeParms !== null ) {
       
   160                 foreach ($this->_dictionary->FDecodeParms->getKeys() as $paramKey) {
       
   161                     $dictionaryArray['FDecodeParms'][0][$paramKey] =
       
   162                           $this->_dictionary->FDecodeParms->items[$paramKey]->value;
       
   163                 }
       
   164             }
       
   165         }
       
   166 
       
   167         return $dictionaryArray;
       
   168     }
       
   169 
       
   170     /**
       
   171      * Decode stream
       
   172      *
       
   173      * @throws Zend_Pdf_Exception
       
   174      */
       
   175     private function _decodeStream()
       
   176     {
       
   177         if ($this->_initialDictionaryData === null) {
       
   178             $this->_initialDictionaryData = $this->_extractDictionaryData();
       
   179         }
       
   180 
       
   181         /**
       
   182          * All applied stream filters must be processed to decode stream.
       
   183          * If we don't recognize any of applied filetrs an exception should be thrown here
       
   184          */
       
   185         if (isset($this->_initialDictionaryData['F'])) {
       
   186             /** @todo Check, how external files can be processed. */
       
   187             require_once 'Zend/Pdf/Exception.php';
       
   188             throw new Zend_Pdf_Exception('External filters are not supported now.');
       
   189         }
       
   190 
       
   191         foreach ($this->_initialDictionaryData['Filter'] as $id => $filterName ) {
       
   192             $valueRef = &$this->_value->value->getRef();
       
   193             $this->_value->value->touch();
       
   194             switch ($filterName) {
       
   195                 case 'ASCIIHexDecode':
       
   196                     require_once 'Zend/Pdf/Filter/AsciiHex.php';
       
   197                     $valueRef = Zend_Pdf_Filter_AsciiHex::decode($valueRef);
       
   198                     break;
       
   199 
       
   200                 case 'ASCII85Decode':
       
   201                     require_once 'Zend/Pdf/Filter/Ascii85.php';
       
   202                     $valueRef = Zend_Pdf_Filter_Ascii85::decode($valueRef);
       
   203                     break;
       
   204 
       
   205                 case 'FlateDecode':
       
   206                     require_once 'Zend/Pdf/Filter/Compression/Flate.php';
       
   207                     $valueRef = Zend_Pdf_Filter_Compression_Flate::decode($valueRef,
       
   208                                                                           $this->_initialDictionaryData['DecodeParms'][$id]);
       
   209                     break;
       
   210 
       
   211                 case 'LZWDecode':
       
   212                     require_once 'Zend/Pdf/Filter/Compression/Lzw.php';
       
   213                     $valueRef = Zend_Pdf_Filter_Compression_Lzw::decode($valueRef,
       
   214                                                                         $this->_initialDictionaryData['DecodeParms'][$id]);
       
   215                     break;
       
   216 
       
   217                 case 'RunLengthDecode':
       
   218                     require_once 'Zend/Pdf/Filter/RunLength.php';
       
   219                     $valueRef = Zend_Pdf_Filter_RunLength::decode($valueRef);
       
   220                     break;
       
   221 
       
   222                 default:
       
   223                     require_once 'Zend/Pdf/Exception.php';
       
   224                     throw new Zend_Pdf_Exception('Unknown stream filter: \'' . $filterName . '\'.');
       
   225             }
       
   226         }
       
   227 
       
   228         $this->_streamDecoded = true;
       
   229     }
       
   230 
       
   231     /**
       
   232      * Encode stream
       
   233      *
       
   234      * @throws Zend_Pdf_Exception
       
   235      */
       
   236     private function _encodeStream()
       
   237     {
       
   238         /**
       
   239          * All applied stream filters must be processed to encode stream.
       
   240          * If we don't recognize any of applied filetrs an exception should be thrown here
       
   241          */
       
   242         if (isset($this->_initialDictionaryData['F'])) {
       
   243             /** @todo Check, how external files can be processed. */
       
   244             require_once 'Zend/Pdf/Exception.php';
       
   245             throw new Zend_Pdf_Exception('External filters are not supported now.');
       
   246         }
       
   247 
       
   248         $filters = array_reverse($this->_initialDictionaryData['Filter'], true);
       
   249 
       
   250         foreach ($filters as $id => $filterName ) {
       
   251             $valueRef = &$this->_value->value->getRef();
       
   252             $this->_value->value->touch();
       
   253             switch ($filterName) {
       
   254                 case 'ASCIIHexDecode':
       
   255                     require_once 'Zend/Pdf/Filter/AsciiHex.php';
       
   256                     $valueRef = Zend_Pdf_Filter_AsciiHex::encode($valueRef);
       
   257                     break;
       
   258 
       
   259                 case 'ASCII85Decode':
       
   260                     require_once 'Zend/Pdf/Filter/Ascii85.php';
       
   261                     $valueRef = Zend_Pdf_Filter_Ascii85::encode($valueRef);
       
   262                     break;
       
   263 
       
   264                 case 'FlateDecode':
       
   265                     require_once 'Zend/Pdf/Filter/Compression/Flate.php';
       
   266                     $valueRef = Zend_Pdf_Filter_Compression_Flate::encode($valueRef,
       
   267                                                                           $this->_initialDictionaryData['DecodeParms'][$id]);
       
   268                     break;
       
   269 
       
   270                 case 'LZWDecode':
       
   271                     require_once 'Zend/Pdf/Filter/Compression/Lzw.php';
       
   272                     $valueRef = Zend_Pdf_Filter_Compression_Lzw::encode($valueRef,
       
   273                                                                         $this->_initialDictionaryData['DecodeParms'][$id]);
       
   274                     break;
       
   275 
       
   276                  case 'RunLengthDecode':
       
   277                     require_once 'Zend/Pdf/Filter/RunLength.php';
       
   278                     $valueRef = Zend_Pdf_Filter_RunLength::encode($valueRef);
       
   279                     break;
       
   280 
       
   281                default:
       
   282                     require_once 'Zend/Pdf/Exception.php';
       
   283                     throw new Zend_Pdf_Exception('Unknown stream filter: \'' . $filterName . '\'.');
       
   284             }
       
   285         }
       
   286 
       
   287         $this->_streamDecoded = false;
       
   288     }
       
   289 
       
   290     /**
       
   291      * Get handler
       
   292      *
       
   293      * @param string $property
       
   294      * @return mixed
       
   295      * @throws Zend_Pdf_Exception
       
   296      */
       
   297     public function __get($property)
       
   298     {
       
   299         if ($property == 'dictionary') {
       
   300             /**
       
   301              * If stream is not decoded yet, then store original decoding options (do it only once).
       
   302              */
       
   303             if (( !$this->_streamDecoded ) && ($this->_initialDictionaryData === null)) {
       
   304                 $this->_initialDictionaryData = $this->_extractDictionaryData();
       
   305             }
       
   306 
       
   307             return $this->_dictionary;
       
   308         }
       
   309 
       
   310         if ($property == 'value') {
       
   311             if (!$this->_streamDecoded) {
       
   312                 $this->_decodeStream();
       
   313             }
       
   314 
       
   315             return $this->_value->value->getRef();
       
   316         }
       
   317 
       
   318         require_once 'Zend/Pdf/Exception.php';
       
   319         throw new Zend_Pdf_Exception('Unknown stream object property requested.');
       
   320     }
       
   321 
       
   322 
       
   323     /**
       
   324      * Set handler
       
   325      *
       
   326      * @param string $property
       
   327      * @param  mixed $value
       
   328      */
       
   329     public function __set($property, $value)
       
   330     {
       
   331         if ($property == 'value') {
       
   332             $valueRef = &$this->_value->value->getRef();
       
   333             $valueRef = $value;
       
   334             $this->_value->value->touch();
       
   335 
       
   336             $this->_streamDecoded = true;
       
   337 
       
   338             return;
       
   339         }
       
   340 
       
   341         require_once 'Zend/Pdf/Exception.php';
       
   342         throw new Zend_Pdf_Exception('Unknown stream object property: \'' . $property . '\'.');
       
   343     }
       
   344 
       
   345 
       
   346     /**
       
   347      * Treat stream data as already encoded
       
   348      */
       
   349     public function skipFilters()
       
   350     {
       
   351         $this->_streamDecoded = false;
       
   352     }
       
   353 
       
   354 
       
   355     /**
       
   356      * Call handler
       
   357      *
       
   358      * @param string $method
       
   359      * @param array  $args
       
   360      * @return mixed
       
   361      */
       
   362     public function __call($method, $args)
       
   363     {
       
   364         if (!$this->_streamDecoded) {
       
   365             $this->_decodeStream();
       
   366         }
       
   367 
       
   368         switch (count($args)) {
       
   369             case 0:
       
   370                 return $this->_value->$method();
       
   371             case 1:
       
   372                 return $this->_value->$method($args[0]);
       
   373             default:
       
   374                 require_once 'Zend/Pdf/Exception.php';
       
   375                 throw new Zend_Pdf_Exception('Unsupported number of arguments');
       
   376         }
       
   377     }
       
   378 
       
   379     /**
       
   380      * Detach PDF object from the factory (if applicable), clone it and attach to new factory.
       
   381      *
       
   382      * @param Zend_Pdf_ElementFactory $factory  The factory to attach
       
   383      * @param array &$processed  List of already processed indirect objects, used to avoid objects duplication
       
   384      * @param integer $mode  Cloning mode (defines filter for objects cloning)
       
   385      * @returns Zend_Pdf_Element
       
   386      */
       
   387     public function makeClone(Zend_Pdf_ElementFactory $factory, array &$processed, $mode)
       
   388     {
       
   389         $id = spl_object_hash($this);
       
   390         if (isset($processed[$id])) {
       
   391             // Do nothing if object is already processed
       
   392             // return it
       
   393             return $processed[$id];
       
   394         }
       
   395 
       
   396         $streamValue      = $this->_value;
       
   397         $streamDictionary = $this->_dictionary->makeClone($factory, $processed, $mode);
       
   398 
       
   399         // Make new empty instance of stream object and register it in $processed container
       
   400         $processed[$id] = $clonedObject = $factory->newStreamObject('');
       
   401 
       
   402         // Copy current object data and state
       
   403         $clonedObject->_dictionary            = $this->_dictionary->makeClone($factory, $processed, $mode);
       
   404         $clonedObject->_value                 = $this->_value->makeClone($factory, $processed, $mode);
       
   405         $clonedObject->_initialDictionaryData = $this->_initialDictionaryData;
       
   406         $clonedObject->_streamDecoded         = $this->_streamDecoded;
       
   407 
       
   408         return  $clonedObject;
       
   409     }
       
   410 
       
   411     /**
       
   412      * Dump object to a string to save within PDF file
       
   413      *
       
   414      * $factory parameter defines operation context.
       
   415      *
       
   416      * @param Zend_Pdf_ElementFactory $factory
       
   417      * @return string
       
   418      */
       
   419     public function dump(Zend_Pdf_ElementFactory $factory)
       
   420     {
       
   421         $shift = $factory->getEnumerationShift($this->_factory);
       
   422 
       
   423         if ($this->_streamDecoded) {
       
   424             $this->_initialDictionaryData = $this->_extractDictionaryData();
       
   425             $this->_encodeStream();
       
   426         } else if ($this->_initialDictionaryData != null) {
       
   427             $newDictionary   = $this->_extractDictionaryData();
       
   428 
       
   429             if ($this->_initialDictionaryData !== $newDictionary) {
       
   430                 $this->_decodeStream();
       
   431                 $this->_initialDictionaryData = $newDictionary;
       
   432                 $this->_encodeStream();
       
   433             }
       
   434         }
       
   435 
       
   436         // Update stream length
       
   437         $this->dictionary->Length->value = $this->_value->length();
       
   438 
       
   439         return  $this->_objNum + $shift . " " . $this->_genNum . " obj \n"
       
   440              .  $this->dictionary->toString($factory) . "\n"
       
   441              .  $this->_value->toString($factory) . "\n"
       
   442              . "endobj\n";
       
   443     }
       
   444 
       
   445     /**
       
   446      * Clean up resources, used by object
       
   447      */
       
   448     public function cleanUp()
       
   449     {
       
   450         $this->_dictionary = null;
       
   451         $this->_value      = null;
       
   452     }
       
   453 }