| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- <?php
- /**
- * Zend Framework
- *
- * LICENSE
- *
- * This source file is subject to the new BSD license that is bundled
- * with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://framework.zend.com/license/new-bsd
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@zend.com so we can send you a copy immediately.
- *
- * @category Zend
- * @package Zend_Pdf
- * @subpackage FileParser
- * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- * @version $Id$
- */
- /** @see Zend_Pdf_FileParser_Image */
- require_once 'Zend/Pdf/FileParser/Image.php';
- /**
- * Abstract base class for Image file parsers.
- *
- * @package Zend_Pdf
- * @subpackage FileParser
- * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- */
- class Zend_Pdf_FileParser_Image_Png extends Zend_Pdf_FileParser_Image
- {
- protected $_isPNG;
- protected $_width;
- protected $_height;
- protected $_bits;
- protected $_color;
- protected $_compression;
- protected $_preFilter;
- protected $_interlacing;
- protected $_imageData;
- protected $_paletteData;
- protected $_transparencyData;
- /**** Public Interface ****/
- public function getWidth() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_width;
- }
- public function getHeight() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_width;
- }
- public function getBitDepth() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_bits;
- }
- public function getColorSpace() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_color;
- }
- public function getCompressionStrategy() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_compression;
- }
- public function getPaethFilter() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_preFilter;
- }
- public function getInterlacingMode() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_interlacing;
- }
- public function getRawImageData() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_imageData;
- }
- public function getRawPaletteData() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_paletteData;
- }
- public function getRawTransparencyData() {
- if(!$this->_isParsed) {
- $this->parse();
- }
- return $this->_transparencyData;
- }
- /* Semi-Concrete Class Implementation */
- /**
- * Verifies that the image file is in the expected format.
- *
- * @throws Zend_Pdf_Exception
- */
- public function screen()
- {
- if ($this->_isScreened) {
- return;
- }
- return $this->_checkSignature();
- }
- /**
- * Reads and parses the image data from the file on disk.
- *
- * @throws Zend_Pdf_Exception
- */
- public function parse()
- {
- if ($this->_isParsed) {
- return;
- }
- /* Screen the font file first, if it hasn't been done yet.
- */
- $this->screen();
- $this->_parseIHDRChunk();
- $this->_parseChunks();
- }
- protected function _parseSignature() {
- $this->moveToOffset(1); //Skip the first byte (%)
- if('PNG' != $this->readBytes(3)) {
- $this->_isPNG = false;
- } else {
- $this->_isPNG = true;
- }
- }
- protected function _checkSignature() {
- if(!isset($this->_isPNG)) {
- $this->_parseSignature();
- }
- return $this->_isPNG;
- }
- protected function _parseChunks() {
- $this->moveToOffset(33); //Variable chunks start at the end of IHDR
- //Start processing chunks. If there are no more bytes to read parsing is complete.
- $size = $this->getSize();
- while($size - $this->getOffset() >= 8) {
- $chunkLength = $this->readUInt(4);
- if($chunkLength < 0 || ($chunkLength + $this->getOffset() + 4) > $size) {
- require_once 'Zend/Pdf/Exception.php';
- throw new Zend_Pdf_Exception("PNG Corrupt: Invalid Chunk Size In File.");
- }
- $chunkType = $this->readBytes(4);
- $offset = $this->getOffset();
- //If we know how to process the chunk, do it here, else ignore the chunk and move on to the next
- switch($chunkType) {
- case 'IDAT': // This chunk may appear more than once. It contains the actual image data.
- $this->_parseIDATChunk($offset, $chunkLength);
- break;
- case 'PLTE': // This chunk contains the image palette.
- $this->_parsePLTEChunk($offset, $chunkLength);
- break;
- case 'tRNS': // This chunk contains non-alpha channel transparency data
- $this->_parseTRNSChunk($offset, $chunkLength);
- break;
- case 'IEND':
- break 2; //End the loop too
- //@TODO Implement the rest of the PNG chunks. (There are many not implemented here)
- }
- if($offset + $chunkLength + 4 < $size) {
- $this->moveToOffset($offset + $chunkLength + 4); //Skip past the data finalizer. (Don't rely on the parse to leave the offsets correct)
- }
- }
- if(empty($this->_imageData)) {
- require_once 'Zend/Pdf/Exception.php';
- throw new Zend_Pdf_Exception ( "This PNG is corrupt. All png must contain IDAT chunks." );
- }
- }
- protected function _parseIHDRChunk() {
- $this->moveToOffset(12); //IHDR must always start at offset 12 and run for 17 bytes
- if(!$this->readBytes(4) == 'IHDR') {
- require_once 'Zend/Pdf/Exception.php';
- throw new Zend_Pdf_Exception( "This PNG is corrupt. The first chunk in a PNG file must be IHDR." );
- }
- $this->_width = $this->readUInt(4);
- $this->_height = $this->readUInt(4);
- $this->_bits = $this->readInt(1);
- $this->_color = $this->readInt(1);
- $this->_compression = $this->readInt(1);
- $this->_preFilter = $this->readInt(1);
- $this->_interlacing = $this->readInt(1);
- if($this->_interlacing != Zend_Pdf_Image::PNG_INTERLACING_DISABLED) {
- require_once 'Zend/Pdf/Exception.php';
- throw new Zend_Pdf_Exception( "Only non-interlaced images are currently supported." );
- }
- }
- protected function _parseIDATChunk($chunkOffset, $chunkLength) {
- $this->moveToOffset($chunkOffset);
- if(!isset($this->_imageData)) {
- $this->_imageData = $this->readBytes($chunkLength);
- } else {
- $this->_imageData .= $this->readBytes($chunkLength);
- }
- }
- protected function _parsePLTEChunk($chunkOffset, $chunkLength) {
- $this->moveToOffset($chunkOffset);
- $this->_paletteData = $this->readBytes($chunkLength);
- }
- protected function _parseTRNSChunk($chunkOffset, $chunkLength) {
- $this->moveToOffset($chunkOffset);
- //Processing of tRNS data varies dependending on the color depth
- switch($this->_color) {
- case Zend_Pdf_Image::PNG_CHANNEL_GRAY:
- $baseColor = $this->readInt(1);
- $this->_transparencyData = array($baseColor, $baseColor);
- break;
- case Zend_Pdf_Image::PNG_CHANNEL_RGB:
- //@TODO Fix this hack.
- //This parser cheats and only uses the lsb's (and only works with < 16 bit depth images)
- /*
- From the standard:
- For color type 2 (truecolor), the tRNS chunk contains a single RGB color value, stored in the format:
- Red: 2 bytes, range 0 .. (2^bitdepth)-1
- Green: 2 bytes, range 0 .. (2^bitdepth)-1
- Blue: 2 bytes, range 0 .. (2^bitdepth)-1
- (If the image bit depth is less than 16, the least significant bits are used and the others are 0.)
- Pixels of the specified color value are to be treated as transparent (equivalent to alpha value 0);
- all other pixels are to be treated as fully opaque (alpha value 2bitdepth-1).
- */
- $red = $this->readInt(1);
- $this->skipBytes(1);
- $green = $this->readInt(1);
- $this->skipBytes(1);
- $blue = $this->readInt(1);
- $this->_transparencyData = array($red, $red, $green, $green, $blue, $blue);
- break;
- case Zend_Pdf_Image::PNG_CHANNEL_INDEXED:
- //@TODO Fix this hack.
- //This parser cheats too. It only masks the first color in the palette.
- /*
- From the standard:
- For color type 3 (indexed color), the tRNS chunk contains a series of one-byte alpha values, corresponding to entries in the PLTE chunk:
- Alpha for palette index 0: 1 byte
- Alpha for palette index 1: 1 byte
- ...etc...
- Each entry indicates that pixels of the corresponding palette index must be treated as having the specified alpha value.
- Alpha values have the same interpretation as in an 8-bit full alpha channel: 0 is fully transparent, 255 is fully opaque,
- regardless of image bit depth. The tRNS chunk must not contain more alpha values than there are palette entries,
- but tRNS can contain fewer values than there are palette entries. In this case, the alpha value for all remaining palette
- entries is assumed to be 255. In the common case in which only palette index 0 need be made transparent, only a one-byte
- tRNS chunk is needed.
- */
- $tmpData = $this->readBytes($chunkLength);
- if(($trnsIdx = strpos($tmpData, "\0")) !== false) {
- $this->_transparencyData = array($trnsIdx, $trnsIdx);
- }
- break;
- case Zend_Pdf_Image::PNG_CHANNEL_GRAY_ALPHA:
- //Fall through to the next case
- case Zend_Pdf_Image::PNG_CHANNEL_RGB_ALPHA:
- require_once 'Zend/Pdf/Exception.php';
- throw new Zend_Pdf_Exception( "tRNS chunk illegal for Alpha Channel Images" );
- break;
- }
- }
- }
|