Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Png.php
Go to the documentation of this file.
1 <?php
24 #require_once 'Zend/Pdf/FileParser/Image.php';
25 
26 
36 {
37  protected $_isPNG;
38  protected $_width;
39  protected $_height;
40  protected $_bits;
41  protected $_color;
42  protected $_compression;
43  protected $_preFilter;
44  protected $_interlacing;
45 
46  protected $_imageData;
47  protected $_paletteData;
48  protected $_transparencyData;
49 
50  /**** Public Interface ****/
51 
52  public function getWidth() {
53  if(!$this->_isParsed) {
54  $this->parse();
55  }
56  return $this->_width;
57  }
58 
59  public function getHeight() {
60  if(!$this->_isParsed) {
61  $this->parse();
62  }
63  return $this->_width;
64  }
65 
66  public function getBitDepth() {
67  if(!$this->_isParsed) {
68  $this->parse();
69  }
70  return $this->_bits;
71  }
72 
73  public function getColorSpace() {
74  if(!$this->_isParsed) {
75  $this->parse();
76  }
77  return $this->_color;
78  }
79 
80  public function getCompressionStrategy() {
81  if(!$this->_isParsed) {
82  $this->parse();
83  }
84  return $this->_compression;
85  }
86 
87  public function getPaethFilter() {
88  if(!$this->_isParsed) {
89  $this->parse();
90  }
91  return $this->_preFilter;
92  }
93 
94  public function getInterlacingMode() {
95  if(!$this->_isParsed) {
96  $this->parse();
97  }
98  return $this->_interlacing;
99  }
100 
101  public function getRawImageData() {
102  if(!$this->_isParsed) {
103  $this->parse();
104  }
105  return $this->_imageData;
106  }
107 
108  public function getRawPaletteData() {
109  if(!$this->_isParsed) {
110  $this->parse();
111  }
112  return $this->_paletteData;
113  }
114 
115  public function getRawTransparencyData() {
116  if(!$this->_isParsed) {
117  $this->parse();
118  }
120  }
121 
122  /* Semi-Concrete Class Implementation */
123 
129  public function screen()
130  {
131  if ($this->_isScreened) {
132  return;
133  }
134  return $this->_checkSignature();
135  }
136 
142  public function parse()
143  {
144  if ($this->_isParsed) {
145  return;
146  }
147 
148  /* Screen the font file first, if it hasn't been done yet.
149  */
150  $this->screen();
151 
152  $this->_parseIHDRChunk();
153  $this->_parseChunks();
154  }
155 
156 
157  protected function _parseSignature() {
158  $this->moveToOffset(1); //Skip the first byte (%)
159  if('PNG' != $this->readBytes(3)) {
160  $this->_isPNG = false;
161  } else {
162  $this->_isPNG = true;
163  }
164  }
165 
166  protected function _checkSignature() {
167  if(!isset($this->_isPNG)) {
168  $this->_parseSignature();
169  }
170  return $this->_isPNG;
171  }
172 
173  protected function _parseChunks() {
174  $this->moveToOffset(33); //Variable chunks start at the end of IHDR
175 
176  //Start processing chunks. If there are no more bytes to read parsing is complete.
177  $size = $this->getSize();
178  while($size - $this->getOffset() >= 8) {
179  $chunkLength = $this->readUInt(4);
180  if($chunkLength < 0 || ($chunkLength + $this->getOffset() + 4) > $size) {
181  #require_once 'Zend/Pdf/Exception.php';
182  throw new Zend_Pdf_Exception("PNG Corrupt: Invalid Chunk Size In File.");
183  }
184 
185  $chunkType = $this->readBytes(4);
186  $offset = $this->getOffset();
187 
188  //If we know how to process the chunk, do it here, else ignore the chunk and move on to the next
189  switch($chunkType) {
190  case 'IDAT': // This chunk may appear more than once. It contains the actual image data.
191  $this->_parseIDATChunk($offset, $chunkLength);
192  break;
193 
194  case 'PLTE': // This chunk contains the image palette.
195  $this->_parsePLTEChunk($offset, $chunkLength);
196  break;
197 
198  case 'tRNS': // This chunk contains non-alpha channel transparency data
199  $this->_parseTRNSChunk($offset, $chunkLength);
200  break;
201 
202  case 'IEND':
203  break 2; //End the loop too
204 
205  //@TODO Implement the rest of the PNG chunks. (There are many not implemented here)
206  }
207  if($offset + $chunkLength + 4 < $size) {
208  $this->moveToOffset($offset + $chunkLength + 4); //Skip past the data finalizer. (Don't rely on the parse to leave the offsets correct)
209  }
210  }
211  if(empty($this->_imageData)) {
212  #require_once 'Zend/Pdf/Exception.php';
213  throw new Zend_Pdf_Exception ( "This PNG is corrupt. All png must contain IDAT chunks." );
214  }
215  }
216 
217  protected function _parseIHDRChunk() {
218  $this->moveToOffset(12); //IHDR must always start at offset 12 and run for 17 bytes
219  if(!$this->readBytes(4) == 'IHDR') {
220  #require_once 'Zend/Pdf/Exception.php';
221  throw new Zend_Pdf_Exception( "This PNG is corrupt. The first chunk in a PNG file must be IHDR." );
222  }
223  $this->_width = $this->readUInt(4);
224  $this->_height = $this->readUInt(4);
225  $this->_bits = $this->readInt(1);
226  $this->_color = $this->readInt(1);
227  $this->_compression = $this->readInt(1);
228  $this->_preFilter = $this->readInt(1);
229  $this->_interlacing = $this->readInt(1);
230  if($this->_interlacing != Zend_Pdf_Image::PNG_INTERLACING_DISABLED) {
231  #require_once 'Zend/Pdf/Exception.php';
232  throw new Zend_Pdf_Exception( "Only non-interlaced images are currently supported." );
233  }
234  }
235 
236  protected function _parseIDATChunk($chunkOffset, $chunkLength) {
237  $this->moveToOffset($chunkOffset);
238  if(!isset($this->_imageData)) {
239  $this->_imageData = $this->readBytes($chunkLength);
240  } else {
241  $this->_imageData .= $this->readBytes($chunkLength);
242  }
243  }
244 
245  protected function _parsePLTEChunk($chunkOffset, $chunkLength) {
246  $this->moveToOffset($chunkOffset);
247  $this->_paletteData = $this->readBytes($chunkLength);
248  }
249 
250  protected function _parseTRNSChunk($chunkOffset, $chunkLength) {
251  $this->moveToOffset($chunkOffset);
252 
253  //Processing of tRNS data varies dependending on the color depth
254 
255  switch($this->_color) {
257  $baseColor = $this->readInt(1);
258  $this->_transparencyData = array($baseColor, $baseColor);
259  break;
260 
262 
263  //@TODO Fix this hack.
264  //This parser cheats and only uses the lsb's (and only works with < 16 bit depth images)
265 
266  /*
267  From the standard:
268 
269  For color type 2 (truecolor), the tRNS chunk contains a single RGB color value, stored in the format:
270 
271  Red: 2 bytes, range 0 .. (2^bitdepth)-1
272  Green: 2 bytes, range 0 .. (2^bitdepth)-1
273  Blue: 2 bytes, range 0 .. (2^bitdepth)-1
274 
275  (If the image bit depth is less than 16, the least significant bits are used and the others are 0.)
276  Pixels of the specified color value are to be treated as transparent (equivalent to alpha value 0);
277  all other pixels are to be treated as fully opaque (alpha value 2bitdepth-1).
278 
279  */
280 
281  $red = $this->readInt(1);
282  $this->skipBytes(1);
283  $green = $this->readInt(1);
284  $this->skipBytes(1);
285  $blue = $this->readInt(1);
286 
287  $this->_transparencyData = array($red, $red, $green, $green, $blue, $blue);
288 
289  break;
290 
292 
293  //@TODO Fix this hack.
294  //This parser cheats too. It only masks the first color in the palette.
295 
296  /*
297  From the standard:
298 
299  For color type 3 (indexed color), the tRNS chunk contains a series of one-byte alpha values, corresponding to entries in the PLTE chunk:
300 
301  Alpha for palette index 0: 1 byte
302  Alpha for palette index 1: 1 byte
303  ...etc...
304 
305  Each entry indicates that pixels of the corresponding palette index must be treated as having the specified alpha value.
306  Alpha values have the same interpretation as in an 8-bit full alpha channel: 0 is fully transparent, 255 is fully opaque,
307  regardless of image bit depth. The tRNS chunk must not contain more alpha values than there are palette entries,
308  but tRNS can contain fewer values than there are palette entries. In this case, the alpha value for all remaining palette
309  entries is assumed to be 255. In the common case in which only palette index 0 need be made transparent, only a one-byte
310  tRNS chunk is needed.
311 
312  */
313 
314  $tmpData = $this->readBytes($chunkLength);
315  if(($trnsIdx = strpos($tmpData, "\0")) !== false) {
316  $this->_transparencyData = array($trnsIdx, $trnsIdx);
317  }
318 
319  break;
320 
322  //Fall through to the next case
324  #require_once 'Zend/Pdf/Exception.php';
325  throw new Zend_Pdf_Exception( "tRNS chunk illegal for Alpha Channel Images" );
326  break;
327  }
328  }
329 }
const PNG_INTERLACING_DISABLED
Definition: Image.php:96
readInt($size, $byteOrder=Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN)
Definition: FileParser.php:228
_parseTRNSChunk($chunkOffset, $chunkLength)
Definition: Png.php:250
_parseIDATChunk($chunkOffset, $chunkLength)
Definition: Png.php:236
const PNG_CHANNEL_RGB
Definition: Image.php:100
_parsePLTEChunk($chunkOffset, $chunkLength)
Definition: Png.php:245
const PNG_CHANNEL_GRAY_ALPHA
Definition: Image.php:102
readBytes($byteCount)
Definition: FileParser.php:195
const PNG_CHANNEL_RGB_ALPHA
Definition: Image.php:103
skipBytes($byteCount)
Definition: FileParser.php:206
const PNG_CHANNEL_INDEXED
Definition: Image.php:101
readUInt($size, $byteOrder=Zend_Pdf_FileParser::BYTE_ORDER_BIG_ENDIAN)
Definition: FileParser.php:303
const PNG_CHANNEL_GRAY
Definition: Image.php:99