/** * Render the completed PDF to a string. * If $newSegmentOnly is true, then only appended part of PDF is returned. * * @param boolean $newSegmentOnly * @return string */ public function render($newSegmentOnly = false) { $this->_dumpPages(); // 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) { return ''; } else { return $this->_trailer->getPDFString(); } } // offset (from a start of PDF file) of new PDF file segment $segmentOffset = $this->_trailer->getPDFLength(); // new PDF file segment itself $pdfSegment = ''; // 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; // 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", $segmentOffset + strlen($pdfSegment), $updateInfo->getGenNum()); $pdfSegment .= $updateInfo->getObjectDump(); } $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; } } $xrefStartOffset = $segmentOffset + strlen($pdfSegment); $this->_trailer->Size->value = $this->_objFactory->getObjectCount(); $pdfSegment .= $xrefTableStr . $this->_trailer->toString() . "startxref\n" . $xrefStartOffset . "\n" . "%%EOF\n"; if ($newSegmentOnly) { return $pdfSegment; } else { return $this->_trailer->getPDFString() . $pdfSegment; } }
/** * Render the completed PDF to a string. * If $newSegmentOnly is true and it's not a new document, * 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) { if ($this->_isNewDocument) { // Drop full document first time even $newSegmentOnly is set to true $newSegmentOnly = false; $this->_isNewDocument = false; } // Save document properties if necessary if ($this->properties != $this->_originalProperties) { $docInfo = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); foreach ($this->properties as $key => $value) { switch ($key) { case 'Trapped': switch ($value) { case true: $docInfo->$key = new Zend_Pdf_Element_Name('True'); break; case false: $docInfo->$key = new Zend_Pdf_Element_Name('False'); break; case null: $docInfo->$key = new Zend_Pdf_Element_Name('Unknown'); break; default: require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception('Wrong Trapped document property vale: \'' . $value . '\'. Only true, false and null values are allowed.'); break; } case 'CreationDate': // break intentionally omitted case 'ModDate': $docInfo->$key = new Zend_Pdf_Element_String((string)$value); break; case 'Title': // break intentionally omitted case 'Author': // break intentionally omitted case 'Subject': // break intentionally omitted case 'Keywords': // break intentionally omitted case 'Creator': // break intentionally omitted case 'Producer': if (extension_loaded('mbstring') === true) { $detected = mb_detect_encoding($value); if ($detected !== 'ASCII') { $value = "\xfe\xff" . mb_convert_encoding($value, 'UTF-16', $detected); } } $docInfo->$key = new Zend_Pdf_Element_String((string)$value); break; default: // Set property using PDF type based on PHP type $docInfo->$key = Zend_Pdf_Element::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 ''; } }