/** * Object constructor. * * If resource is not a Zend_Pdf_Element object, then stream object with specified value is * generated. * * @param Zend_Pdf_Element|string $resource */ public function __construct($resource) { $this->_objectFactory = Zend_Pdf_ElementFactory::createFactory(1); if ($resource instanceof Zend_Pdf_Element) { $this->_resource = $this->_objectFactory->newObject($resource); } else { $this->_resource = $this->_objectFactory->newStreamObject($resource); } }
/** * Object constructor. * * If resource is not a Zend_Pdf_Element object, then stream object with specified value is * generated. * * @param Zend_Pdf_Element|string $resource */ public function __construct($resource) { if ($resource instanceof Zend_Pdf_Element_Object) { $this->_objectFactory = $resource->getFactory(); $this->_resource = $resource; return; } require_once 'Zend/Pdf/ElementFactory.php'; $this->_objectFactory = Zend_Pdf_ElementFactory::createFactory(1); if ($resource instanceof Zend_Pdf_Element) { $this->_resource = $this->_objectFactory->newObject($resource); } else { $this->_resource = $this->_objectFactory->newStreamObject($resource); } }
/** * Object constructor. * * @param Zend_Pdf_Element_Object $extGStateObject * @throws Zend_Pdf_Exception */ public function __construct(Zend_Pdf_Element_Object $extGStateObject = null) { if ($extGStateObject == null) { // Create new Graphics State object require_once 'Zend/Pdf/ElementFactory.php'; $factory = Zend_Pdf_ElementFactory::createFactory(1); $gsDictionary = new Zend_Pdf_Element_Dictionary(); $gsDictionary->Type = new Zend_Pdf_Element_Name('ExtGState'); $extGStateObject = $factory->newObject($gsDictionary); } if ($extGStateObject->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception('Graphics state PDF object must be a dictionary'); } parent::__construct($gsDictionary); }
/** * Object constructor. * Constructor signatures: * * 1. Load PDF page from a parsed PDF file. * Object factory is created by PDF parser. * --------------------------------------------------------- * new Zend_Pdf_Page(Zend_Pdf_Element_Dictionary $pageDict, * Zend_Pdf_ElementFactory_Interface $factory); * --------------------------------------------------------- * * 2. Clone PDF page. * New page is created in the same context as source page. Object factory is shared. * Thus it will be attached to the document, but need to be placed into Zend_Pdf::$pages array * to be included into output. * --------------------------------------------------------- * new Zend_Pdf_Page(Zend_Pdf_Page $page); * --------------------------------------------------------- * * 3. Create new page with a specified pagesize. * If $factory is null then it will be created and page must be attached to the document to be * included into output. * --------------------------------------------------------- * new Zend_Pdf_Page(string $pagesize, Zend_Pdf_ElementFactory_Interface $factory = null); * --------------------------------------------------------- * * 4. Create new page with a specified pagesize (in default user space units). * If $factory is null then it will be created and page must be attached to the document to be * included into output. * --------------------------------------------------------- * new Zend_Pdf_Page(numeric $width, numeric $height, Zend_Pdf_ElementFactory_Interface $factory = null); * --------------------------------------------------------- * * * @param mixed $param1 * @param mixed $param2 * @param mixed $param3 * @throws Zend_Pdf_Exception */ public function __construct($param1, $param2 = null, $param3 = null) { if ($param1 instanceof Zend_Pdf_Element_Reference && $param1->getType() == Zend_Pdf_Element::TYPE_DICTIONARY && $param2 instanceof Zend_Pdf_ElementFactory_Interface && $param3 === null) { $this->_pageDictionary = $param1; $this->_objFactory = $param2; $this->_attached = true; $this->_safeGS = false; return; } else { if ($param1 instanceof Zend_Pdf_Page && $param2 === null && $param3 === null) { // Clone existing page. // Let already existing content and resources to be shared between pages // We don't give existing content modification functionality, so we don't need "deep copy" $this->_objFactory = $param1->_objFactory; $this->_attached =& $param1->_attached; $this->_safeGS = false; $this->_pageDictionary = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); foreach ($param1->_pageDictionary->getKeys() as $key) { if ($key == 'Contents') { // Clone Contents property $this->_pageDictionary->Contents = new Zend_Pdf_Element_Array(); if ($param1->_pageDictionary->Contents->getType() != Zend_Pdf_Element::TYPE_ARRAY) { // Prepare array of content streams and add existing stream $this->_pageDictionary->Contents->items[] = $param1->_pageDictionary->Contents; } else { // Clone array of the content streams foreach ($param1->_pageDictionary->Contents->items as $srcContentStream) { $this->_pageDictionary->Contents->items[] = $srcContentStream; } } } else { $this->_pageDictionary->{$key} = $param1->_pageDictionary->{$key}; } } return; } else { if (is_string($param1) && ($param2 === null || $param2 instanceof Zend_Pdf_ElementFactory_Interface) && $param3 === null) { if ($param2 !== null) { $this->_objFactory = $param2; } else { //require_once 'Zend/Pdf/ElementFactory.php'; $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); } $this->_attached = false; $this->_safeGS = true; /** New page created. That's users App responsibility to track GS changes */ switch (strtolower($param1)) { case 'a4': $param1 = Zend_Pdf_Page::SIZE_A4; break; case 'a4-landscape': $param1 = Zend_Pdf_Page::SIZE_A4_LANDSCAPE; break; case 'letter': $param1 = Zend_Pdf_Page::SIZE_LETTER; break; case 'letter-landscape': $param1 = Zend_Pdf_Page::SIZE_LETTER_LANDSCAPE; break; default: // should be in "x:y" or "x:y:" form } $pageDim = explode(':', $param1); if (count($pageDim) == 2 || count($pageDim) == 3) { $pageWidth = $pageDim[0]; $pageHeight = $pageDim[1]; } else { /** * @todo support of user defined pagesize notations, like: * "210x297mm", "595x842", "8.5x11in", "612x792" */ //require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception('Wrong pagesize notation.'); } /** * @todo support of pagesize recalculation to "default user space units" */ } else { if (is_numeric($param1) && is_numeric($param2) && ($param3 === null || $param3 instanceof Zend_Pdf_ElementFactory_Interface)) { if ($param3 !== null) { $this->_objFactory = $param3; } else { //require_once 'Zend/Pdf/ElementFactory.php'; $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); } $this->_attached = false; $this->_safeGS = true; /** New page created. That's users App responsibility to track GS changes */ $pageWidth = $param1; $pageHeight = $param2; } else { //require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception('Unrecognized method signature, wrong number of arguments or wrong argument types.'); } } } } $this->_pageDictionary = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); $this->_pageDictionary->Type = new Zend_Pdf_Element_Name('Page'); //require_once 'Zend/Pdf.php'; $this->_pageDictionary->LastModified = new Zend_Pdf_Element_String(Zend_Pdf::pdfDate()); $this->_pageDictionary->Resources = new Zend_Pdf_Element_Dictionary(); $this->_pageDictionary->MediaBox = new Zend_Pdf_Element_Array(); $this->_pageDictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0); $this->_pageDictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0); $this->_pageDictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageWidth); $this->_pageDictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageHeight); $this->_pageDictionary->Contents = new Zend_Pdf_Element_Array(); }
/** * Object constructor. * Constructor signatures: * * 1. Load PDF page from a parsed PDF file. * Object factory is created by PDF parser. * --------------------------------------------------------- * new Zend_Pdf_Page(Zend_Pdf_Element_Dictionary $pageDict, * Zend_Pdf_ElementFactory_Interface $factory); * --------------------------------------------------------- * * 2. Clone PDF page. * New page is created in the same context as source page. Object factory is shared. * Thus it will be attached to the document, but need to be placed into Zend_Pdf::$pages array * to be included into output. * --------------------------------------------------------- * new Zend_Pdf_Page(Zend_Pdf_Page $page); * --------------------------------------------------------- * * 3. Create new page with a specified pagesize. * If $factory is null then it will be created and page must be attached to the document to be * included into output. * --------------------------------------------------------- * new Zend_Pdf_Page(string $pagesize, Zend_Pdf_ElementFactory_Interface $factory = null); * --------------------------------------------------------- * * 4. Create new page with a specified pagesize (in default user space units). * If $factory is null then it will be created and page must be attached to the document to be * included into output. * --------------------------------------------------------- * new Zend_Pdf_Page(numeric $width, numeric $height, Zend_Pdf_ElementFactory_Interface $factory = null); * --------------------------------------------------------- * * * @param mixed $param1 * @param mixed $param2 * @param mixed $param3 * @throws Zend_Pdf_Exception */ public function __construct($param1, $param2 = null, $param3 = null) { if ($param1 instanceof Zend_Pdf_Element_Reference && $param1->getType() == Zend_Pdf_Element::TYPE_DICTIONARY && $param2 instanceof Zend_Pdf_ElementFactory_Interface && $param3 === null) { $this->_pageDictionary = $param1; $this->_objFactory = $param2; $this->_attached = true; return; } else { if ($param1 instanceof Zend_Pdf_Page && $param2 === null && $param3 === null) { /** @todo implementation */ throw new Zend_Pdf_Exception('Not implemented yet.'); } else { if (is_string($param1) && ($param2 === null || $param2 instanceof Zend_Pdf_ElementFactory_Interface) && $param3 === null) { $this->_objFactory = $param2 !== null ? $param2 : Zend_Pdf_ElementFactory::createFactory(1); $this->_attached = false; switch (strtolower($param1)) { case 'a4': $param1 = Zend_Pdf_Page::SIZE_A4; break; case 'a4-landscape': $param1 = Zend_Pdf_Page::SIZE_A4_LANDSCAPE; break; case 'letter': $param1 = Zend_Pdf_Page::SIZE_LETTER; break; case 'letter-landscape': $param1 = Zend_Pdf_Page::SIZE_LETTER_LANDSCAPE; break; default: // should be in "x:y" form } $pageDim = explode(':', $param1); if (count($pageDim) == 3) { $pageWidth = $pageDim[0]; $pageHeight = $pageDim[1]; } else { /** * @todo support of user defined pagesize notations, like: * "210x297mm", "595x842", "8.5x11in", "612x792" */ throw new Zend_Pdf_Exception('Wrong pagesize notation.'); } /** * @todo support of pagesize recalculation to "default user space units" */ } else { if (is_numeric($param1) && is_numeric($param2) && ($param3 === null || $param3 instanceof Zend_Pdf_ElementFactory_Interface)) { $this->_objFactory = $param3 !== null ? $param3 : Zend_Pdf_ElementFactory::createFactory(1); $this->_attached = false; $pageWidth = $param1; $pageHeight = $param2; } else { throw new Zend_Pdf_Exception('Unrecognized method signature, wrong number of arguments or wrong argument types.'); } } } } $this->_pageDictionary = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); $this->_pageDictionary->Type = new Zend_Pdf_Element_Name('Page'); $this->_pageDictionary->LastModified = new Zend_Pdf_Element_String(Zend_Pdf::pdfDate()); $this->_pageDictionary->Resources = new Zend_Pdf_Element_Dictionary(); $this->_pageDictionary->MediaBox = new Zend_Pdf_Element_Array(); $this->_pageDictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0); $this->_pageDictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric(0); $this->_pageDictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageWidth); $this->_pageDictionary->MediaBox->items[] = new Zend_Pdf_Element_Numeric($pageHeight); $this->_pageDictionary->Contents = new Zend_Pdf_Element_Array(); }
/** * Creates or loads PDF document. * * If $source is null, then it creates a new document. * * If $source is a string and $load is false, then it loads document * from a binary string. * * If $source is a string and $load is true, then it loads document * from a file. * $revision used to roll back document to specified version * (0 - current version, 1 - previous version, 2 - ...) * * @param string $source - PDF file to load * @param integer $revision * @throws Zend_Pdf_Exception * @return Zend_Pdf */ public function __construct($source = null, $revision = null, $load = false) { require_once 'Zend/Pdf/ElementFactory.php'; $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); if ($source !== null) { require_once 'Zend/Pdf/Parser.php'; $this->_parser = new Zend_Pdf_Parser($source, $this->_objFactory, $load); $this->_pdfHeaderVersion = $this->_parser->getPDFVersion(); $this->_trailer = $this->_parser->getTrailer(); if ($this->_trailer->Encrypt !== null) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception('Encrypted document modification is not supported'); } if ($revision !== null) { $this->rollback($revision); } else { $this->_loadPages($this->_trailer->Root->Pages); } $this->_loadNamedDestinations($this->_trailer->Root, $this->_parser->getPDFVersion()); $this->_loadOutlines($this->_trailer->Root); if ($this->_trailer->Info !== null) { $this->properties = $this->_trailer->Info->toPhp(); if (isset($this->properties['Trapped'])) { switch ($this->properties['Trapped']) { case 'True': $this->properties['Trapped'] = true; break; case 'False': $this->properties['Trapped'] = false; break; case 'Unknown': $this->properties['Trapped'] = null; break; default: // Wrong property value // Do nothing break; } } $this->_originalProperties = $this->properties; } $this->_isNewDocument = false; } else { $this->_pdfHeaderVersion = Zend_Pdf::PDF_VERSION; $trailerDictionary = new Zend_Pdf_Element_Dictionary(); /** * Document id */ $docId = md5(uniqid(rand(), true)); // 32 byte (128 bit) identifier $docIdLow = substr($docId, 0, 16); // first 16 bytes $docIdHigh = substr($docId, 16, 16); // second 16 bytes $trailerDictionary->ID = new Zend_Pdf_Element_Array(); $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdLow); $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdHigh); $trailerDictionary->Size = new Zend_Pdf_Element_Numeric(0); require_once 'Zend/Pdf/Trailer/Generator.php'; $this->_trailer = new Zend_Pdf_Trailer_Generator($trailerDictionary); /** * Document catalog indirect object. */ $docCatalog = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); $docCatalog->Type = new Zend_Pdf_Element_Name('Catalog'); $docCatalog->Version = new Zend_Pdf_Element_Name(Zend_Pdf::PDF_VERSION); $this->_trailer->Root = $docCatalog; /** * Pages container */ $docPages = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); $docPages->Type = new Zend_Pdf_Element_Name('Pages'); $docPages->Kids = new Zend_Pdf_Element_Array(); $docPages->Count = new Zend_Pdf_Element_Numeric(0); $docCatalog->Pages = $docPages; } }
/** * Object constructor * * @param string $imageFileName * @throws Zend_Pdf_Exception * @todo Add compression conversions to support compression strategys other than PNG_COMPRESSION_DEFAULT_STRATEGY. * @todo Add pre-compression filtering. * @todo Add interlaced image handling. * @todo Add support for 16-bit images. Requires PDF version bump to 1.5 at least. * @todo Add processing for all PNG chunks defined in the spec. gAMA etc. * @todo Fix tRNS chunk support for Indexed Images to a SMask. */ public function __construct($imageFileName) { if (($imageFile = @fopen($imageFileName, 'rb')) === false) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception("Can not open '{$imageFileName}' file for reading."); } parent::__construct(); //Check if the file is a PNG fseek($imageFile, 1, SEEK_CUR); //First signature byte (%) if ('PNG' != fread($imageFile, 3)) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception('Image is not a PNG'); } fseek($imageFile, 12, SEEK_CUR); //Signature bytes (Includes the IHDR chunk) IHDR processed linerarly because it doesnt contain a variable chunk length $wtmp = unpack('Ni', fread($imageFile, 4)); //Unpack a 4-Byte Long $width = $wtmp['i']; $htmp = unpack('Ni', fread($imageFile, 4)); $height = $htmp['i']; $bits = ord(fread($imageFile, 1)); //Higher than 8 bit depths are only supported in later versions of PDF. $color = ord(fread($imageFile, 1)); $compression = ord(fread($imageFile, 1)); $prefilter = ord(fread($imageFile, 1)); if (($interlacing = ord(fread($imageFile, 1))) != Zend_Pdf_Resource_Image_Png::PNG_INTERLACING_DISABLED) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception("Only non-interlaced images are currently supported."); } $this->_width = $width; $this->_height = $height; $this->_imageProperties = array(); $this->_imageProperties['bitDepth'] = $bits; $this->_imageProperties['pngColorType'] = $color; $this->_imageProperties['pngFilterType'] = $prefilter; $this->_imageProperties['pngCompressionType'] = $compression; $this->_imageProperties['pngInterlacingType'] = $interlacing; fseek($imageFile, 4, SEEK_CUR); //4 Byte Ending Sequence $imageData = ''; /* * The following loop processes PNG chunks. 4 Byte Longs are packed first give the chunk length * followed by the chunk signature, a four byte code. IDAT and IEND are manditory in any PNG. */ while (!feof($imageFile)) { $chunkLengthBytes = fread($imageFile, 4); if ($chunkLengthBytes === false) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception('Error ocuured while image file reading.'); } $chunkLengthtmp = unpack('Ni', $chunkLengthBytes); $chunkLength = $chunkLengthtmp['i']; $chunkType = fread($imageFile, 4); switch ($chunkType) { case 'IDAT': //Image Data /* * Reads the actual image data from the PNG file. Since we know at this point that the compression * strategy is the default strategy, we also know that this data is Zip compressed. We will either copy * the data directly to the PDF and provide the correct FlateDecode predictor, or decompress the data * decode the filters and output the data as a raw pixel map. */ $imageData .= fread($imageFile, $chunkLength); fseek($imageFile, 4, SEEK_CUR); break; case 'PLTE': //Palette $paletteData = fread($imageFile, $chunkLength); fseek($imageFile, 4, SEEK_CUR); break; case 'tRNS': //Basic (non-alpha channel) transparency. $trnsData = fread($imageFile, $chunkLength); switch ($color) { case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY: $baseColor = ord(substr($trnsData, 1, 1)); $transparencyData = array(new Zend_Pdf_Element_Numeric($baseColor), new Zend_Pdf_Element_Numeric($baseColor)); break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB: $red = ord(substr($trnsData, 1, 1)); $green = ord(substr($trnsData, 3, 1)); $blue = ord(substr($trnsData, 5, 1)); $transparencyData = array(new Zend_Pdf_Element_Numeric($red), new Zend_Pdf_Element_Numeric($red), new Zend_Pdf_Element_Numeric($green), new Zend_Pdf_Element_Numeric($green), new Zend_Pdf_Element_Numeric($blue), new Zend_Pdf_Element_Numeric($blue)); break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_INDEXED: //Find the first transparent color in the index, we will mask that. (This is a bit of a hack. This should be a SMask and mask all entries values). if (($trnsIdx = strpos($trnsData, "")) !== false) { $transparencyData = array(new Zend_Pdf_Element_Numeric($trnsIdx), new Zend_Pdf_Element_Numeric($trnsIdx)); } break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY_ALPHA: // Fall through to the next case // Fall through to the next case case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB_ALPHA: require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception("tRNS chunk illegal for Alpha Channel Images"); break; } fseek($imageFile, 4, SEEK_CUR); //4 Byte Ending Sequence break; case 'IEND': break 2; //End the loop too //End the loop too default: fseek($imageFile, $chunkLength + 4, SEEK_CUR); //Skip the section break; } } fclose($imageFile); $compressed = true; $imageDataTmp = ''; $smaskData = ''; switch ($color) { case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB: $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB'); break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY: $colorSpace = new Zend_Pdf_Element_Name('DeviceGray'); break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_INDEXED: if (empty($paletteData)) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception("PNG Corruption: No palette data read for indexed type PNG."); } $colorSpace = new Zend_Pdf_Element_Array(); $colorSpace->items[] = new Zend_Pdf_Element_Name('Indexed'); $colorSpace->items[] = new Zend_Pdf_Element_Name('DeviceRGB'); $colorSpace->items[] = new Zend_Pdf_Element_Numeric(strlen($paletteData) / 3 - 1); $paletteObject = $this->_objectFactory->newObject(new Zend_Pdf_Element_String_Binary($paletteData)); $colorSpace->items[] = $paletteObject; break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY_ALPHA: /* * To decode PNG's with alpha data we must create two images from one. One image will contain the Gray data * the other will contain the Gray transparency overlay data. The former will become the object data and the latter * will become the Shadow Mask (SMask). */ if ($bits > 8) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception("Alpha PNGs with bit depth > 8 are not yet supported"); } $colorSpace = new Zend_Pdf_Element_Name('DeviceGray'); require_once 'Zend/Pdf/ElementFactory.php'; $decodingObjFactory = Zend_Pdf_ElementFactory::createFactory(1); $decodingStream = $decodingObjFactory->newStreamObject($imageData); $decodingStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); $decodingStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary(); $decodingStream->dictionary->DecodeParms->Predictor = new Zend_Pdf_Element_Numeric(15); $decodingStream->dictionary->DecodeParms->Columns = new Zend_Pdf_Element_Numeric($width); $decodingStream->dictionary->DecodeParms->Colors = new Zend_Pdf_Element_Numeric(2); //GreyAlpha $decodingStream->dictionary->DecodeParms->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); $decodingStream->skipFilters(); $pngDataRawDecoded = $decodingStream->value; //Iterate every pixel and copy out gray data and alpha channel (this will be slow) for ($pixel = 0, $pixelcount = $width * $height; $pixel < $pixelcount; $pixel++) { $imageDataTmp .= $pngDataRawDecoded[$pixel * 2]; $smaskData .= $pngDataRawDecoded[$pixel * 2 + 1]; } $compressed = false; $imageData = $imageDataTmp; //Overwrite image data with the gray channel without alpha break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB_ALPHA: /* * To decode PNG's with alpha data we must create two images from one. One image will contain the RGB data * the other will contain the Gray transparency overlay data. The former will become the object data and the latter * will become the Shadow Mask (SMask). */ if ($bits > 8) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception("Alpha PNGs with bit depth > 8 are not yet supported"); } $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB'); require_once 'Zend/Pdf/ElementFactory.php'; $decodingObjFactory = Zend_Pdf_ElementFactory::createFactory(1); $decodingStream = $decodingObjFactory->newStreamObject($imageData); $decodingStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); $decodingStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary(); $decodingStream->dictionary->DecodeParms->Predictor = new Zend_Pdf_Element_Numeric(15); $decodingStream->dictionary->DecodeParms->Columns = new Zend_Pdf_Element_Numeric($width); $decodingStream->dictionary->DecodeParms->Colors = new Zend_Pdf_Element_Numeric(4); //RGBA $decodingStream->dictionary->DecodeParms->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); $decodingStream->skipFilters(); $pngDataRawDecoded = $decodingStream->value; //Iterate every pixel and copy out rgb data and alpha channel (this will be slow) for ($pixel = 0, $pixelcount = $width * $height; $pixel < $pixelcount; $pixel++) { $imageDataTmp .= $pngDataRawDecoded[$pixel * 4 + 0] . $pngDataRawDecoded[$pixel * 4 + 1] . $pngDataRawDecoded[$pixel * 4 + 2]; $smaskData .= $pngDataRawDecoded[$pixel * 4 + 3]; } $compressed = false; $imageData = $imageDataTmp; //Overwrite image data with the RGB channel without alpha break; default: require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception("PNG Corruption: Invalid color space."); } if (empty($imageData)) { require_once 'Zend/Pdf/Exception.php'; throw new Zend_Pdf_Exception("Corrupt PNG Image. Mandatory IDAT chunk not found."); } $imageDictionary = $this->_resource->dictionary; if (!empty($smaskData)) { /* * Includes the Alpha transparency data as a Gray Image, then assigns the image as the Shadow Mask for the main image data. */ $smaskStream = $this->_objectFactory->newStreamObject($smaskData); $smaskStream->dictionary->Type = new Zend_Pdf_Element_Name('XObject'); $smaskStream->dictionary->Subtype = new Zend_Pdf_Element_Name('Image'); $smaskStream->dictionary->Width = new Zend_Pdf_Element_Numeric($width); $smaskStream->dictionary->Height = new Zend_Pdf_Element_Numeric($height); $smaskStream->dictionary->ColorSpace = new Zend_Pdf_Element_Name('DeviceGray'); $smaskStream->dictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); $imageDictionary->SMask = $smaskStream; // Encode stream with FlateDecode filter $smaskStreamDecodeParms = array(); $smaskStreamDecodeParms['Predictor'] = new Zend_Pdf_Element_Numeric(15); $smaskStreamDecodeParms['Columns'] = new Zend_Pdf_Element_Numeric($width); $smaskStreamDecodeParms['Colors'] = new Zend_Pdf_Element_Numeric(1); $smaskStreamDecodeParms['BitsPerComponent'] = new Zend_Pdf_Element_Numeric(8); $smaskStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary($smaskStreamDecodeParms); $smaskStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); } if (!empty($transparencyData)) { //This is experimental and not properly tested. $imageDictionary->Mask = new Zend_Pdf_Element_Array($transparencyData); } $imageDictionary->Width = new Zend_Pdf_Element_Numeric($width); $imageDictionary->Height = new Zend_Pdf_Element_Numeric($height); $imageDictionary->ColorSpace = $colorSpace; $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); $imageDictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); $decodeParms = array(); $decodeParms['Predictor'] = new Zend_Pdf_Element_Numeric(15); // Optimal prediction $decodeParms['Columns'] = new Zend_Pdf_Element_Numeric($width); $decodeParms['Colors'] = new Zend_Pdf_Element_Numeric($color == Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB || $color == Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB_ALPHA ? 3 : 1); $decodeParms['BitsPerComponent'] = new Zend_Pdf_Element_Numeric($bits); $imageDictionary->DecodeParms = new Zend_Pdf_Element_Dictionary($decodeParms); //Include only the image IDAT section data. $this->_resource->value = $imageData; //Skip double compression if ($compressed) { $this->_resource->skipFilters(); } }
/** * Clone page, extract it and dependent objects from the current document, * so it can be used within other docs. */ public function __clone() { $factory = Zend_Pdf_ElementFactory::createFactory(1); $processed = array(); // Clone dictionary object. // Do it explicitly to prevent sharing page attributes between different // results of clonePage() operation (other resources are still shared) $dictionary = new Zend_Pdf_Element_Dictionary(); foreach ($this->_dictionary->getKeys() as $key) { $dictionary->{$key} = $this->_dictionary->{$key}->makeClone($factory->getFactory(), $processed, Zend_Pdf_Element::CLONE_MODE_SKIP_PAGES); } $this->_dictionary = $factory->newObject($dictionary); $this->_objFactory = $factory; $this->_attached = false; $this->_style = null; $this->_font = null; }
/** * Object constructor. */ public function __construct() { $this->_factory = Zend_Pdf_ElementFactory::createFactory(1); $this->_processed = array(); }
/** * Creates or loads PDF document. * * If $source is null, then it creates a new document. * * If $source is a string and $load is false, then it loads document * from a binary string. * * If $source is a string and $load is true, then it loads document * from a file. * $revision used to roll back document to specified version * (0 - currtent version, 1 - previous version, 2 - ...) * * @param string $source - PDF file to load * @param integer $revision * @throws Zend_Pdf_Exception * @return Zend_Pdf */ public function __construct($source = null, $revision = null, $load = false) { $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); if ($source !== null) { $this->_parser = new Zend_Pdf_Parser($source, $this->_objFactory, $load); $this->_trailer = $this->_parser->getTrailer(); if ($revision !== null) { $this->rollback($revision); } else { $this->_loadPages($this->_trailer->Root->Pages); } if ($this->_trailer->Info !== null) { foreach ($this->_trailer->Info->getKeys() as $key) { $this->properties[$key] = $this->_trailer->Info->{$key}->value; } if (isset($this->properties['Trapped'])) { switch ($this->properties['Trapped']) { case 'True': $this->properties['Trapped'] = true; break; case 'False': $this->properties['Trapped'] = false; break; case 'Unknown': $this->properties['Trapped'] = null; break; default: // Wrong property value // Do nothing break; } } $this->_originalProperties = $this->properties; } } else { $trailerDictionary = new Zend_Pdf_Element_Dictionary(); /** * Document id */ $docId = md5(uniqid(rand(), true)); // 32 byte (128 bit) identifier $docIdLow = substr($docId, 0, 16); // first 16 bytes $docIdHigh = substr($docId, 16, 16); // second 16 bytes $trailerDictionary->ID = new Zend_Pdf_Element_Array(); $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdLow); $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdHigh); $trailerDictionary->Size = new Zend_Pdf_Element_Numeric(0); $this->_trailer = new Zend_Pdf_Trailer_Generator($trailerDictionary); /** * Document catalog indirect object. */ $docCatalog = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); $docCatalog->Type = new Zend_Pdf_Element_Name('Catalog'); $docCatalog->Version = new Zend_Pdf_Element_Name(Zend_Pdf::PDF_VERSION); $this->_trailer->Root = $docCatalog; /** * Pages container */ $docPages = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); $docPages->Type = new Zend_Pdf_Element_Name('Pages'); $docPages->Kids = new Zend_Pdf_Element_Array(); $docPages->Count = new Zend_Pdf_Element_Numeric(0); $docCatalog->Pages = $docPages; } }
/** * Creates or loads PDF document. * * If $source is null, then it creates a new document. * * If $source is a string and $load is false, then it loads document * from a binary string. * * If $source is a string and $load is true, then it loads document * from a file. * $revision used to roll back document to specified version * (0 - currtent version, 1 - previous version, 2 - ...) * * @param string $source - PDF file to load * @param integer $revision * @throws Zend_Pdf_Exception * @return Zend_Pdf */ public function __construct($source = null, $revision = null, $load = false) { $this->_objFactory = Zend_Pdf_ElementFactory::createFactory(1); if ($source !== null) { $this->_parser = new Zend_Pdf_Parser($source, $this->_objFactory, $load); $this->_trailer = $this->_parser->getTrailer(); if ($revision !== null) { $this->rollback($revision); } else { $this->_loadPages($this->_trailer->Root->Pages); } } else { $trailerDictionary = new Zend_Pdf_Element_Dictionary(); /** * Document id */ $docId = md5(uniqid(rand(), true)); // 32 byte (128 bit) identifier $docIdLow = substr($docId, 0, 16); // first 16 bytes $docIdHigh = substr($docId, 16, 16); // second 16 bytes $trailerDictionary->ID = new Zend_Pdf_Element_Array(); $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdLow); $trailerDictionary->ID->items[] = new Zend_Pdf_Element_String_Binary($docIdHigh); $trailerDictionary->Size = new Zend_Pdf_Element_Numeric(0); $this->_trailer = new Zend_Pdf_Trailer_Generator($trailerDictionary); /** * Document catalog indirect object. */ $docCatalog = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); $docCatalog->Type = new Zend_Pdf_Element_Name('Catalog'); $docCatalog->Version = new Zend_Pdf_Element_Name(Zend_Pdf::PDF_VERSION); $this->_trailer->Root = $docCatalog; /** * Pages container */ $docPages = $this->_objFactory->newObject(new Zend_Pdf_Element_Dictionary()); $docPages->Type = new Zend_Pdf_Element_Name('Pages'); $docPages->Kids = new Zend_Pdf_Element_Array(); $docPages->Count = new Zend_Pdf_Element_Numeric(0); $docCatalog->Pages = $docPages; } }
public function __construct($imageFileName) { if (($imageFile = @fopen($imageFileName, 'rb')) === false) { throw new Zend_Pdf_Exception("Can not open '{$imageFileName}' file for reading."); } parent::__construct(); fseek($imageFile, 1, SEEK_CUR); if ('PNG' != fread($imageFile, 3)) { throw new Zend_Pdf_Exception('Image is not a PNG'); } fseek($imageFile, 12, SEEK_CUR); $wtmp = unpack('Ni', fread($imageFile, 4)); $width = $wtmp['i']; $htmp = unpack('Ni', fread($imageFile, 4)); $height = $htmp['i']; $bits = ord(fread($imageFile, 1)); $color = ord(fread($imageFile, 1)); $compression = ord(fread($imageFile, 1)); $prefilter = ord(fread($imageFile, 1)); if (($interlacing = ord(fread($imageFile, 1))) != Zend_Pdf_Resource_Image_Png::PNG_INTERLACING_DISABLED) { throw new Zend_Pdf_Exception("Only non-interlaced images are currently supported."); } $this->_width = $width; $this->_height = $height; $this->_imageProperties = array(); $this->_imageProperties['bitDepth'] = $bits; $this->_imageProperties['pngColorType'] = $color; $this->_imageProperties['pngFilterType'] = $prefilter; $this->_imageProperties['pngCompressionType'] = $compression; $this->_imageProperties['pngInterlacingType'] = $interlacing; fseek($imageFile, 4, SEEK_CUR); $imageData = ''; while (!feof($imageFile)) { $chunkLengthBytes = fread($imageFile, 4); if ($chunkLengthBytes === false) { throw new Zend_Pdf_Exception('Error ocuured while image file reading.'); } $chunkLengthtmp = unpack('Ni', $chunkLengthBytes); $chunkLength = $chunkLengthtmp['i']; $chunkType = fread($imageFile, 4); switch ($chunkType) { case 'IDAT': $imageData .= fread($imageFile, $chunkLength); fseek($imageFile, 4, SEEK_CUR); break; case 'PLTE': $paletteData = fread($imageFile, $chunkLength); fseek($imageFile, 4, SEEK_CUR); break; case 'tRNS': $trnsData = fread($imageFile, $chunkLength); switch ($color) { case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY: $baseColor = ord(substr($trnsData, 1, 1)); $transparencyData = array(new Zend_Pdf_Element_Numeric($baseColor), new Zend_Pdf_Element_Numeric($baseColor)); break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB: $red = ord(substr($trnsData, 1, 1)); $green = ord(substr($trnsData, 3, 1)); $blue = ord(substr($trnsData, 5, 1)); $transparencyData = array(new Zend_Pdf_Element_Numeric($red), new Zend_Pdf_Element_Numeric($red), new Zend_Pdf_Element_Numeric($green), new Zend_Pdf_Element_Numeric($green), new Zend_Pdf_Element_Numeric($blue), new Zend_Pdf_Element_Numeric($blue)); break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_INDEXED: if (($trnsIdx = strpos($trnsData, "")) !== false) { $transparencyData = array(new Zend_Pdf_Element_Numeric($trnsIdx), new Zend_Pdf_Element_Numeric($trnsIdx)); } break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY_ALPHA: case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB_ALPHA: throw new Zend_Pdf_Exception("tRNS chunk illegal for Alpha Channel Images"); break; } fseek($imageFile, 4, SEEK_CUR); break; case 'IEND': break 2; default: fseek($imageFile, $chunkLength + 4, SEEK_CUR); break; } } fclose($imageFile); $compressed = true; $imageDataTmp = ''; $smaskData = ''; switch ($color) { case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB: $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB'); break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY: $colorSpace = new Zend_Pdf_Element_Name('DeviceGray'); break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_INDEXED: if (empty($paletteData)) { throw new Zend_Pdf_Exception("PNG Corruption: No palette data read for indexed type PNG."); } $colorSpace = new Zend_Pdf_Element_Array(); $colorSpace->items[] = new Zend_Pdf_Element_Name('Indexed'); $colorSpace->items[] = new Zend_Pdf_Element_Name('DeviceRGB'); $colorSpace->items[] = new Zend_Pdf_Element_Numeric(strlen($paletteData) / 3 - 1); $paletteObject = $this->_objectFactory->newObject(new Zend_Pdf_Element_String_Binary($paletteData)); $colorSpace->items[] = $paletteObject; break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_GRAY_ALPHA: if ($bits > 8) { throw new Zend_Pdf_Exception("Alpha PNGs with bit depth > 8 are not yet supported"); } $colorSpace = new Zend_Pdf_Element_Name('DeviceGray'); $decodingObjFactory = Zend_Pdf_ElementFactory::createFactory(1); $decodingStream = $decodingObjFactory->newStreamObject($imageData); $decodingStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); $decodingStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary(); $decodingStream->dictionary->DecodeParms->Predictor = new Zend_Pdf_Element_Numeric(15); $decodingStream->dictionary->DecodeParms->Columns = new Zend_Pdf_Element_Numeric($width); $decodingStream->dictionary->DecodeParms->Colors = new Zend_Pdf_Element_Numeric(2); $decodingStream->dictionary->DecodeParms->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); $decodingStream->skipFilters(); $pngDataRawDecoded = $decodingStream->value; for ($pixel = 0, $pixelcount = $width * $height; $pixel < $pixelcount; $pixel++) { $imageDataTmp .= $pngDataRawDecoded[$pixel * 2]; $smaskData .= $pngDataRawDecoded[$pixel * 2 + 1]; } $compressed = false; $imageData = $imageDataTmp; break; case Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB_ALPHA: if ($bits > 8) { throw new Zend_Pdf_Exception("Alpha PNGs with bit depth > 8 are not yet supported"); } $colorSpace = new Zend_Pdf_Element_Name('DeviceRGB'); $decodingObjFactory = Zend_Pdf_ElementFactory::createFactory(1); $decodingStream = $decodingObjFactory->newStreamObject($imageData); $decodingStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); $decodingStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary(); $decodingStream->dictionary->DecodeParms->Predictor = new Zend_Pdf_Element_Numeric(15); $decodingStream->dictionary->DecodeParms->Columns = new Zend_Pdf_Element_Numeric($width); $decodingStream->dictionary->DecodeParms->Colors = new Zend_Pdf_Element_Numeric(4); $decodingStream->dictionary->DecodeParms->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); $decodingStream->skipFilters(); $pngDataRawDecoded = $decodingStream->value; for ($pixel = 0, $pixelcount = $width * $height; $pixel < $pixelcount; $pixel++) { $imageDataTmp .= $pngDataRawDecoded[$pixel * 4 + 0] . $pngDataRawDecoded[$pixel * 4 + 1] . $pngDataRawDecoded[$pixel * 4 + 2]; $smaskData .= $pngDataRawDecoded[$pixel * 4 + 3]; } $compressed = false; $imageData = $imageDataTmp; break; default: throw new Zend_Pdf_Exception("PNG Corruption: Invalid color space."); } if (empty($imageData)) { throw new Zend_Pdf_Exception("Corrupt PNG Image. Mandatory IDAT chunk not found."); } $imageDictionary = $this->_resource->dictionary; if (!empty($smaskData)) { $smaskStream = $this->_objectFactory->newStreamObject($smaskData); $smaskStream->dictionary->Type = new Zend_Pdf_Element_Name('XObject'); $smaskStream->dictionary->Subtype = new Zend_Pdf_Element_Name('Image'); $smaskStream->dictionary->Width = new Zend_Pdf_Element_Numeric($width); $smaskStream->dictionary->Height = new Zend_Pdf_Element_Numeric($height); $smaskStream->dictionary->ColorSpace = new Zend_Pdf_Element_Name('DeviceGray'); $smaskStream->dictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); $imageDictionary->SMask = $smaskStream; $smaskStreamDecodeParms = array(); $smaskStreamDecodeParms['Predictor'] = new Zend_Pdf_Element_Numeric(15); $smaskStreamDecodeParms['Columns'] = new Zend_Pdf_Element_Numeric($width); $smaskStreamDecodeParms['Colors'] = new Zend_Pdf_Element_Numeric(1); $smaskStreamDecodeParms['BitsPerComponent'] = new Zend_Pdf_Element_Numeric(8); $smaskStream->dictionary->DecodeParms = new Zend_Pdf_Element_Dictionary($smaskStreamDecodeParms); $smaskStream->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); } if (!empty($transparencyData)) { $imageDictionary->Mask = new Zend_Pdf_Element_Array($transparencyData); } $imageDictionary->Width = new Zend_Pdf_Element_Numeric($width); $imageDictionary->Height = new Zend_Pdf_Element_Numeric($height); $imageDictionary->ColorSpace = $colorSpace; $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($bits); $imageDictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode'); $decodeParms = array(); $decodeParms['Predictor'] = new Zend_Pdf_Element_Numeric(15); $decodeParms['Columns'] = new Zend_Pdf_Element_Numeric($width); $decodeParms['Colors'] = new Zend_Pdf_Element_Numeric($color == Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB || $color == Zend_Pdf_Resource_Image_Png::PNG_CHANNEL_RGB_ALPHA ? 3 : 1); $decodeParms['BitsPerComponent'] = new Zend_Pdf_Element_Numeric($bits); $imageDictionary->DecodeParms = new Zend_Pdf_Element_Dictionary($decodeParms); $this->_resource->value = $imageData; if ($compressed) { $this->_resource->skipFilters(); } }