Ejemplo n.º 1
0
 /**
  * Object constructor.
  *
  * If resource is not a \Zend\PDF\InternalType\AbstractTypeObject object,
  * then stream object with specified value is generated.
  *
  * @param \Zend\PDF\InternalType\AbstractTypeObject|string $resource
  */
 public function __construct($resource)
 {
     $this->_objectFactory = ObjectFactory\ObjectFactory::createFactory(1);
     if ($resource instanceof InternalType\AbstractTypeObject) {
         $this->_resource = $this->_objectFactory->newObject($resource);
     } else {
         $this->_resource = $this->_objectFactory->newStreamObject($resource);
     }
 }
Ejemplo n.º 2
0
 /**
  * Render the completed PDF to a string.
  * If $newSegmentOnly is true, then only appended part of PDF is returned.
  *
  * @param boolean $newSegmentOnly
  * @param resource $outputStream
  * @return string
  * @throws \Zend\PDF\Exception
  */
 public function render($newSegmentOnly = false, $outputStream = null)
 {
     // Save document properties if necessary
     if ($this->properties != $this->_originalProperties) {
         $docInfo = $this->_objFactory->newObject(new InternalType\DictionaryObject());
         foreach ($this->properties as $key => $value) {
             switch ($key) {
                 case 'Trapped':
                     switch ($value) {
                         case true:
                             $docInfo->{$key} = new InternalType\NameObject('True');
                             break;
                         case false:
                             $docInfo->{$key} = new InternalType\NameObject('False');
                             break;
                         case null:
                             $docInfo->{$key} = new InternalType\NameObject('Unknown');
                             break;
                         default:
                             throw new Exception('Wrong Trapped document property vale: \'' . $value . '\'. Only true, false and null values are allowed.');
                             break;
                     }
                 case 'CreationDate':
                     // break intentionally omitted
                 // break intentionally omitted
                 case 'ModDate':
                     $docInfo->{$key} = new InternalType\StringObject((string) $value);
                     break;
                 case 'Title':
                     // break intentionally omitted
                 // break intentionally omitted
                 case 'Author':
                     // break intentionally omitted
                 // break intentionally omitted
                 case 'Subject':
                     // break intentionally omitted
                 // break intentionally omitted
                 case 'Keywords':
                     // break intentionally omitted
                 // break intentionally omitted
                 case 'Creator':
                     // break intentionally omitted
                 // break intentionally omitted
                 case 'Producer':
                     if (extension_loaded('mbstring') === true) {
                         $detected = mb_detect_encoding($value);
                         if ($detected !== 'ASCII') {
                             $value = chr(254) . chr(255) . mb_convert_encoding($value, 'UTF-16', $detected);
                         }
                     }
                     $docInfo->{$key} = new InternalType\StringObject((string) $value);
                     break;
                 default:
                     // Set property using PDF type based on PHP type
                     $docInfo->{$key} = InternalType\AbstractTypeObject::phpToPDF($value);
                     break;
             }
         }
         $this->_trailer->Info = $docInfo;
     }
     $this->_dumpPages();
     $this->_dumpNamedDestinations();
     $this->_dumpOutlines();
     // Check, that PDF file was modified
     // File is always modified by _dumpPages() now, but future implementations may eliminate this.
     if (!$this->_objFactory->isModified()) {
         if ($newSegmentOnly) {
             // Do nothing, return
             return '';
         }
         if ($outputStream === null) {
             return $this->_trailer->getPDFString();
         } else {
             $pdfData = $this->_trailer->getPDFString();
             while (strlen($pdfData) > 0 && ($byteCount = fwrite($outputStream, $pdfData)) != false) {
                 $pdfData = substr($pdfData, $byteCount);
             }
             return '';
         }
     }
     // offset (from a start of PDF file) of new PDF file segment
     $offset = $this->_trailer->getPDFLength();
     // Last Object number in a list of free objects
     $lastFreeObject = $this->_trailer->getLastFreeObject();
     // Array of cross-reference table subsections
     $xrefTable = array();
     // Object numbers of first objects in each subsection
     $xrefSectionStartNums = array();
     // Last cross-reference table subsection
     $xrefSection = array();
     // Dummy initialization of the first element (specail case - header of linked list of free objects).
     $xrefSection[] = 0;
     $xrefSectionStartNums[] = 0;
     // Object number of last processed PDF object.
     // Used to manage cross-reference subsections.
     // Initialized by zero (specail case - header of linked list of free objects).
     $lastObjNum = 0;
     if ($outputStream !== null) {
         if (!$newSegmentOnly) {
             $pdfData = $this->_trailer->getPDFString();
             while (strlen($pdfData) > 0 && ($byteCount = fwrite($outputStream, $pdfData)) != false) {
                 $pdfData = substr($pdfData, $byteCount);
             }
         }
     } else {
         $pdfSegmentBlocks = $newSegmentOnly ? array() : array($this->_trailer->getPDFString());
     }
     // Iterate objects to create new reference table
     foreach ($this->_objFactory->listModifiedObjects() as $updateInfo) {
         $objNum = $updateInfo->getObjNum();
         if ($objNum - $lastObjNum != 1) {
             // Save cross-reference table subsection and start new one
             $xrefTable[] = $xrefSection;
             $xrefSection = array();
             $xrefSectionStartNums[] = $objNum;
         }
         if ($updateInfo->isFree()) {
             // Free object cross-reference table entry
             $xrefSection[] = sprintf("%010d %05d f \n", $lastFreeObject, $updateInfo->getGenNum());
             $lastFreeObject = $objNum;
         } else {
             // In-use object cross-reference table entry
             $xrefSection[] = sprintf("%010d %05d n \n", $offset, $updateInfo->getGenNum());
             $pdfBlock = $updateInfo->getObjectDump();
             $offset += strlen($pdfBlock);
             if ($outputStream === null) {
                 $pdfSegmentBlocks[] = $pdfBlock;
             } else {
                 while (strlen($pdfBlock) > 0 && ($byteCount = fwrite($outputStream, $pdfBlock)) != false) {
                     $pdfBlock = substr($pdfBlock, $byteCount);
                 }
             }
         }
         $lastObjNum = $objNum;
     }
     // Save last cross-reference table subsection
     $xrefTable[] = $xrefSection;
     // Modify first entry (specail case - header of linked list of free objects).
     $xrefTable[0][0] = sprintf("%010d 65535 f \n", $lastFreeObject);
     $xrefTableStr = "xref\n";
     foreach ($xrefTable as $sectId => $xrefSection) {
         $xrefTableStr .= sprintf("%d %d \n", $xrefSectionStartNums[$sectId], count($xrefSection));
         foreach ($xrefSection as $xrefTableEntry) {
             $xrefTableStr .= $xrefTableEntry;
         }
     }
     $this->_trailer->Size->value = $this->_objFactory->getObjectCount();
     $pdfBlock = $xrefTableStr . $this->_trailer->toString() . "startxref\n" . $offset . "\n" . "%%EOF\n";
     $this->_objFactory->cleanEnumerationShiftCache();
     if ($outputStream === null) {
         $pdfSegmentBlocks[] = $pdfBlock;
         return implode('', $pdfSegmentBlocks);
     } else {
         while (strlen($pdfBlock) > 0 && ($byteCount = fwrite($outputStream, $pdfBlock)) != false) {
             $pdfBlock = substr($pdfBlock, $byteCount);
         }
         return '';
     }
 }
Ejemplo n.º 3
0
 /**
  * Check if PDF file was modified
  *
  * @return boolean
  */
 public function isModified()
 {
     return $this->_factory->isModified();
 }
Ejemplo n.º 4
0
 /**
  * Read inderect object from a PDF stream
  *
  * @param integer $offset
  * @param \Zend\PDF\InternalType\IndirectObjectReference\Context $context
  * @return \Zend\PDF\InternalType\IndirectObject
  */
 public function getObject($offset, IndirectObjectReference\Context $context)
 {
     if ($offset === null) {
         return new InternalType\NullObject();
     }
     // Save current offset to make getObject() reentrant
     $offsetSave = $this->offset;
     $this->offset = $offset;
     $this->_context = $context;
     $this->_elements = array();
     $objNum = $this->readLexeme();
     if (!ctype_digit($objNum)) {
         throw new PDF\Exception(sprintf('PDF file syntax error. Offset - 0x%X. Object number expected.', $this->offset - strlen($objNum)));
     }
     $genNum = $this->readLexeme();
     if (!ctype_digit($genNum)) {
         throw new PDF\Exception(sprintf('PDF file syntax error. Offset - 0x%X. Object generation number expected.', $this->offset - strlen($genNum)));
     }
     $objKeyword = $this->readLexeme();
     if ($objKeyword != 'obj') {
         throw new PDF\Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'obj\' keyword expected.', $this->offset - strlen($objKeyword)));
     }
     $objValue = $this->readElement();
     $nextLexeme = $this->readLexeme();
     if ($nextLexeme == 'endobj') {
         /**
          * Object is not generated by factory (thus it's not marked as modified object).
          * But factory is assigned to the obect.
          */
         $obj = new InternalType\IndirectObject($objValue, (int) $objNum, (int) $genNum, $this->_objFactory->resolve());
         foreach ($this->_elements as $element) {
             $element->setParentObject($obj);
         }
         // Restore offset value
         $this->offset = $offsetSave;
         return $obj;
     }
     /**
      * It's a stream object
      */
     if ($nextLexeme != 'stream') {
         throw new PDF\Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'endobj\' or \'stream\' keywords expected.', $this->offset - strlen($nextLexeme)));
     }
     if (!$objValue instanceof InternalType\DictionaryObject) {
         throw new PDF\Exception(sprintf('PDF file syntax error. Offset - 0x%X. Stream extent must be preceded by stream dictionary.', $this->offset - strlen($nextLexeme)));
     }
     /**
      * References are automatically dereferenced at this moment.
      */
     $streamLength = $objValue->Length->value;
     /**
      * 'stream' keyword must be followed by either cr-lf sequence or lf character only.
      * This restriction gives the possibility to recognize all cases exactly
      */
     if ($this->data[$this->offset] == "\r" && $this->data[$this->offset + 1] == "\n") {
         $this->offset += 2;
     } else {
         if ($this->data[$this->offset] == "\n") {
             $this->offset++;
         } else {
             throw new PDF\Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'stream\' must be followed by either cr-lf sequence or lf character only.', $this->offset - strlen($nextLexeme)));
         }
     }
     $dataOffset = $this->offset;
     $this->offset += $streamLength;
     $nextLexeme = $this->readLexeme();
     if ($nextLexeme != 'endstream') {
         throw new PDF\Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'endstream\' keyword expected.', $this->offset - strlen($nextLexeme)));
     }
     $nextLexeme = $this->readLexeme();
     if ($nextLexeme != 'endobj') {
         throw new PDF\Exception(sprintf('PDF file syntax error. Offset - 0x%X. \'endobj\' keyword expected.', $this->offset - strlen($nextLexeme)));
     }
     $obj = new InternalType\StreamObject(substr($this->data, $dataOffset, $streamLength), (int) $objNum, (int) $genNum, $this->_objFactory->resolve(), $objValue);
     foreach ($this->_elements as $element) {
         $element->setParentObject($obj);
     }
     // Restore offset value
     $this->offset = $offsetSave;
     return $obj;
 }
Ejemplo n.º 5
0
Archivo: Page.php Proyecto: stunti/zf2
 /**
  *
  * @param \Zend\PDF\Annotation\AbstractAnnotation $annotation
  * @return \Zend\PDF\Page
  */
 public function attachAnnotation(Annotation\AbstractAnnotation $annotation)
 {
     $annotationDictionary = $annotation->getResource();
     if (!$annotationDictionary instanceof InternalType\IndirectObject && !$annotationDictionary instanceof InternalType\IndirectObjectReference) {
         $annotationDictionary = $this->_objFactory->newObject($annotationDictionary);
     }
     if ($this->_pageDictionary->Annots === null) {
         $this->_pageDictionary->touch();
         $this->_pageDictionary->Annots = new InternalType\ArrayObject();
     } else {
         $this->_pageDictionary->Annots->touch();
     }
     $this->_pageDictionary->Annots->items[] = $annotationDictionary;
     $annotationDictionary->touch();
     $annotationDictionary->P = $this->_pageDictionary;
     return $this;
 }
Ejemplo n.º 6
0
 /**
  * Attach factory to the current;
  *
  * @param \Zend\PDF\ObjectFactory\ObjectFactoryInterface $factory
  */
 public function attach(ObjectFactoryInterface $factory)
 {
     if ($factory === $this || isset($this->_attachedFactories[$factory->getId()])) {
         /**
          * Don't attach factory twice.
          * We do not check recusively because of nature of attach operation
          * (Pages are always attached to the Documents, Fonts are always attached
          * to the pages even if pages already use Document level object factory and so on)
          */
         return;
     }
     $this->_attachedFactories[$factory->getId()] = $factory;
 }
Ejemplo n.º 7
0
 /**
  * Object constructor
  *
  * Note: PHP duplicates string, which is sent by value, only of it's updated.
  * Thus we don't need to care about overhead
  *
  * @param mixed $source
  * @param \Zend\PDF\ObjectFactory\ObjectFactoryInterface $factory
  * @param boolean $load
  * @throws \Zend\Exception
  */
 public function __construct($source, PDF\ObjectFactory\ObjectFactoryInterface $factory, $load)
 {
     if ($load) {
         if (($pdfFile = @fopen($source, 'rb')) === false) {
             throw new PDF\Exception("Can not open '{$source}' file for reading.");
         }
         $byteCount = filesize($source);
         $data = fread($pdfFile, $byteCount);
         $byteCount -= strlen($data);
         while ($byteCount > 0 && ($nextBlock = fread($pdfFile, $byteCount)) != false) {
             $data .= $nextBlock;
             $byteCount -= strlen($nextBlock);
         }
         fclose($pdfFile);
         $this->_stringParser = new DataParser($data, $factory);
     } else {
         $this->_stringParser = new DataParser($source, $factory);
     }
     $pdfVersionComment = $this->_stringParser->readComment();
     if (substr($pdfVersionComment, 0, 5) != '%PDF-') {
         throw new PDF\Exception('File is not a PDF.');
     }
     $pdfVersion = substr($pdfVersionComment, 5);
     if (version_compare($pdfVersion, '0.9', '<') || version_compare($pdfVersion, '1.61', '>=')) {
         /**
          * @todo
          * To support PDF versions 1.5 (Acrobat 6) and PDF version 1.7 (Acrobat 7)
          * Stream compression filter must be implemented (for compressed object streams).
          * Cross reference streams must be implemented
          */
         throw new PDF\Exception(sprintf('Unsupported PDF version. Zend_PDF supports PDF 1.0-1.4. Current version - \'%f\'', $pdfVersion));
     }
     $this->_pdfVersion = $pdfVersion;
     $this->_stringParser->offset = strrpos($this->_stringParser->data, '%%EOF');
     if ($this->_stringParser->offset === false || strlen($this->_stringParser->data) - $this->_stringParser->offset > 7) {
         throw new PDF\Exception('PDF file syntax error. End-of-fle marker expected at the end of file.');
     }
     $this->_stringParser->offset--;
     /**
      * Go to end of cross-reference table offset
      */
     while (DataParser::isWhiteSpace(ord($this->_stringParser->data[$this->_stringParser->offset])) && $this->_stringParser->offset > 0) {
         $this->_stringParser->offset--;
     }
     /**
      * Go to the start of cross-reference table offset
      */
     while (!DataParser::isWhiteSpace(ord($this->_stringParser->data[$this->_stringParser->offset])) && $this->_stringParser->offset > 0) {
         $this->_stringParser->offset--;
     }
     /**
      * Go to the end of 'startxref' keyword
      */
     while (DataParser::isWhiteSpace(ord($this->_stringParser->data[$this->_stringParser->offset])) && $this->_stringParser->offset > 0) {
         $this->_stringParser->offset--;
     }
     /**
      * Go to the white space (eol marker) before 'startxref' keyword
      */
     $this->_stringParser->offset -= 9;
     $nextLexeme = $this->_stringParser->readLexeme();
     if ($nextLexeme != 'startxref') {
         throw new PDF\Exception(sprintf('PDF file syntax error. \'startxref\' keyword expected. Offset - 0x%X.', $this->_stringParser->offset - strlen($nextLexeme)));
     }
     $startXref = $this->_stringParser->readLexeme();
     if (!ctype_digit($startXref)) {
         throw new PDF\Exception(sprintf('PDF file syntax error. Cross-reference table offset must contain only digits. Offset - 0x%X.', $this->_stringParser->offset - strlen($nextLexeme)));
     }
     $this->_trailer = $this->_loadXRefTable($startXref);
     $factory->setObjectCount($this->_trailer->Size->value);
 }
Ejemplo n.º 8
0
 /**
  * Dump Outline and its child outlines into PDF structures
  *
  * Returns dictionary indirect object or reference
  *
  * @internal
  * @param \Zend\PDF\ObjectFactory\ObjectFactory    $factory object factory for newly created indirect objects
  * @param boolean $updateNavigation  Update navigation flag
  * @param \Zend\PDF\InternalType\AbstractTypeObject $parent   Parent outline dictionary reference
  * @param \Zend\PDF\InternalType\AbstractTypeObject $prev     Previous outline dictionary reference
  * @param SplObjectStorage $processedOutlines  List of already processed outlines
  * @return \Zend\PDF\InternalType\AbstractTypeObject
  * @throws \Zend\PDF\Exception
  */
 public function dumpOutline(ObjectFactory\ObjectFactoryInterface $factory, $updateNavigation, InternalType\AbstractTypeObject $parent, InternalType\AbstractTypeObject $prev = null, \SplObjectStorage $processedOutlines = null)
 {
     if ($processedOutlines === null) {
         $processedOutlines = new \SplObjectStorage();
     }
     $processedOutlines->attach($this);
     $outlineDictionary = $factory->newObject(new InternalType\DictionaryObject());
     $outlineDictionary->Title = new InternalType\StringObject($this->getTitle());
     $target = $this->getTarget();
     if ($target === null) {
         // Do nothing
     } else {
         if ($target instanceof PDF\Destination\AbstractDestination) {
             $outlineDictionary->Dest = $target->getResource();
         } else {
             if ($target instanceof Action\AbstractAction) {
                 $outlineDictionary->A = $target->getResource();
             } else {
                 throw new PDF\Exception('Outline target has to be \\Zend\\PDF\\Destination, \\Zend\\PDF\\Action object or null');
             }
         }
     }
     $color = $this->getColor();
     if ($color !== null) {
         $components = $color->getComponents();
         $colorComponentElements = array(new InternalType\NumericObject($components[0]), new InternalType\NumericObject($components[1]), new InternalType\NumericObject($components[2]));
         $outlineDictionary->C = new InternalType\ArrayObject($colorComponentElements);
     }
     if ($this->isItalic() || $this->isBold()) {
         $outlineDictionary->F = new InternalType\NumericObject(($this->isItalic() ? 1 : 0) | ($this->isBold() ? 2 : 0));
         // Bit 2 - Bold
     }
     $outlineDictionary->Parent = $parent;
     $outlineDictionary->Prev = $prev;
     $lastChild = null;
     foreach ($this->childOutlines as $childOutline) {
         if ($processedOutlines->contains($childOutline)) {
             throw new PDF\Exception('Outlines cyclyc reference is detected.');
         }
         if ($lastChild === null) {
             $lastChild = $childOutline->dumpOutline($factory, true, $outlineDictionary, null, $processedOutlines);
             $outlineDictionary->First = $lastChild;
         } else {
             $childOutlineDictionary = $childOutline->dumpOutline($factory, true, $outlineDictionary, $lastChild, $processedOutlines);
             $lastChild->Next = $childOutlineDictionary;
             $lastChild = $childOutlineDictionary;
         }
     }
     $outlineDictionary->Last = $lastChild;
     if (count($this->childOutlines) != 0) {
         $outlineDictionary->Count = new InternalType\NumericObject(($this->isOpen() ? 1 : -1) * count($this->childOutlines));
     }
     return $outlineDictionary;
 }