Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Tiff.php
Go to the documentation of this file.
1 <?php
23 #require_once 'Zend/Pdf/Element/Array.php';
24 #require_once 'Zend/Pdf/Element/Name.php';
25 #require_once 'Zend/Pdf/Element/Numeric.php';
26 
27 
29 #require_once 'Zend/Pdf/Resource/Image.php';
30 
39 {
45 
47  const TIFF_TAG_IMAGE_LENGTH=257; //Height
54 
64 
72 
73  protected $_width;
74  protected $_height;
75  protected $_imageProperties;
76  protected $_endianType;
77  protected $_fileSize;
78  protected $_bitsPerSample;
79  protected $_compression;
80  protected $_filter;
81  protected $_colorCode;
82  protected $_whiteIsZero;
83  protected $_blackIsZero;
84  protected $_colorSpace;
85  protected $_imageDataOffset;
86  protected $_imageDataLength;
87 
88  const TIFF_ENDIAN_BIG=0;
90 
95 
105  protected function unpackBytes($type, $bytes) {
106  if(!isset($this->_endianType)) {
107  #require_once 'Zend/Pdf/Exception.php';
108  throw new Zend_Pdf_Exception("The unpackBytes function can only be used after the endianness of the file is known");
109  }
110  switch($type) {
112  $format = 'C';
113  $unpacked = unpack($format, $bytes);
114  return $unpacked[1];
115  break;
117  $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'v':'n';
118  $unpacked = unpack($format, $bytes);
119  return $unpacked[1];
120  break;
122  $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'V':'N';
123  $unpacked = unpack($format, $bytes);
124  return $unpacked[1];
125  break;
127  $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'V2':'N2';
128  $unpacked = unpack($format, $bytes);
129  return ($unpacked[1]/$unpacked[2]);
130  break;
131  }
132  }
133 
140  public function __construct($imageFileName)
141  {
142  if (($imageFile = @fopen($imageFileName, 'rb')) === false ) {
143  #require_once 'Zend/Pdf/Exception.php';
144  throw new Zend_Pdf_Exception( "Can not open '$imageFileName' file for reading." );
145  }
146 
147  $byteOrderIndicator = fread($imageFile, 2);
148  if($byteOrderIndicator == 'II') {
150  } else if($byteOrderIndicator == 'MM') {
152  } else {
153  #require_once 'Zend/Pdf/Exception.php';
154  throw new Zend_Pdf_Exception( "Not a tiff file or Tiff corrupt. No byte order indication found" );
155  }
156 
158 
159  if($version != 42) {
160  #require_once 'Zend/Pdf/Exception.php';
161  throw new Zend_Pdf_Exception( "Not a tiff file or Tiff corrupt. Incorrect version number." );
162  }
163  $ifdOffset = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG, fread($imageFile, 4));
164 
165  $fileStats = fstat($imageFile);
166  $this->_fileSize = $fileStats['size'];
167 
168  /*
169  * Tiff files are stored as a series of Image File Directories (IFD) each direcctory
170  * has a specific number of entries each 12 bytes in length. At the end of the directories
171  * is four bytes pointing to the offset of the next IFD.
172  */
173 
174  while($ifdOffset > 0) {
175  if(fseek($imageFile, $ifdOffset, SEEK_SET) == -1 || $ifdOffset+2 >= $this->_fileSize) {
176  #require_once 'Zend/Pdf/Exception.php';
177  throw new Zend_Pdf_Exception("Could not seek to the image file directory as indexed by the file. Likely cause is TIFF corruption. Offset: ". $ifdOffset);
178  }
179 
180  $numDirEntries = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, fread($imageFile, 2));
181 
182  /*
183  * Since we now know how many entries are in this (IFD) we can extract the data.
184  * The format of a TIFF directory entry is:
185  *
186  * 2 bytes (short) tag code; See TIFF_TAG constants at the top for supported values. (There are many more in the spec)
187  * 2 bytes (short) field type
188  * 4 bytes (long) number of values, or value count.
189  * 4 bytes (mixed) data if the data will fit into 4 bytes or an offset if the data is too large.
190  */
191  for($dirEntryIdx = 1; $dirEntryIdx <= $numDirEntries; $dirEntryIdx++) {
192  $tag = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, fread($imageFile, 2));
193  $fieldType = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, fread($imageFile, 2));
194  $valueCount = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG, fread($imageFile, 4));
195 
196  switch($fieldType) {
198  $fieldLength = $valueCount;
199  break;
201  $fieldLength = $valueCount;
202  break;
204  $fieldLength = $valueCount * 2;
205  break;
207  $fieldLength = $valueCount * 4;
208  break;
210  $fieldLength = $valueCount * 8;
211  break;
212  default:
213  $fieldLength = $valueCount;
214  }
215 
216  $offsetBytes = fread($imageFile, 4);
217 
218  if($fieldLength <= 4) {
219  switch($fieldType) {
222  break;
224  //Fall through to next case
227  break;
229  //Fall through to next case
230  default:
232  }
233  } else {
234  $refOffset = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG, $offsetBytes);
235  }
236  /*
237  * Linear tag processing is probably not the best way to do this. I've processed the tags according to the
238  * Tiff 6 specification and make some assumptions about when tags will be < 4 bytes and fit into $value and when
239  * they will be > 4 bytes and require seek/extraction of the offset. Same goes for extracting arrays of data, like
240  * the data offsets and length. This should be fixed in the future.
241  */
242  switch($tag) {
244  $this->_width = $value;
245  break;
247  $this->_height = $value;
248  break;
250  if($valueCount>1) {
251  $fp = ftell($imageFile);
252  fseek($imageFile, $refOffset, SEEK_SET);
253  $this->_bitsPerSample = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_SHORT, fread($imageFile, 2));
254  fseek($imageFile, $fp, SEEK_SET);
255  } else {
256  $this->_bitsPerSample = $value;
257  }
258  break;
260  $this->_compression = $value;
261  switch($value) {
263  $this->_filter = 'None';
264  break;
266  //Fall through to next case
268  //Fall through to next case
270  $this->_filter = 'CCITTFaxDecode';
271  #require_once 'Zend/Pdf/Exception.php';
272  throw new Zend_Pdf_Exception("CCITTFaxDecode Compression Mode Not Currently Supported");
273  break;
275  $this->_filter = 'LZWDecode';
276  #require_once 'Zend/Pdf/Exception.php';
277  throw new Zend_Pdf_Exception("LZWDecode Compression Mode Not Currently Supported");
278  break;
280  $this->_filter = 'DCTDecode'; //Should work, doesnt...
281  #require_once 'Zend/Pdf/Exception.php';
282  throw new Zend_Pdf_Exception("JPEG Compression Mode Not Currently Supported");
283  break;
285  //fall through to next case
287  $this->_filter = 'FlateDecode';
288  #require_once 'Zend/Pdf/Exception.php';
289  throw new Zend_Pdf_Exception("ZIP/Flate Compression Mode Not Currently Supported");
290  break;
292  $this->_filter = 'RunLengthDecode';
293  break;
294  }
295  break;
297  $this->_colorCode = $value;
298  $this->_whiteIsZero = false;
299  $this->_blackIsZero = false;
300  switch($value) {
302  $this->_whiteIsZero = true;
303  $this->_colorSpace = 'DeviceGray';
304  break;
306  $this->_blackIsZero = true;
307  $this->_colorSpace = 'DeviceGray';
308  break;
310  //fall through to next case
312  $this->_colorSpace = 'DeviceRGB';
313  break;
315  $this->_colorSpace = 'Indexed';
316  break;
318  $this->_colorSpace = 'DeviceCMYK';
319  break;
321  $this->_colorSpace = 'Lab';
322  break;
323  default:
324  #require_once 'Zend/Pdf/Exception.php';
325  throw new Zend_Pdf_Exception('TIFF: Unknown or Unsupported Color Type: '. $value);
326  }
327  break;
329  if($valueCount>1) {
330  $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'V*':'N*';
331  $fp = ftell($imageFile);
332  fseek($imageFile, $refOffset, SEEK_SET);
333  $stripOffsetsBytes = fread($imageFile, $fieldLength);
334  $this->_imageDataOffset = unpack($format, $stripOffsetsBytes);
335  fseek($imageFile, $fp, SEEK_SET);
336  } else {
337  $this->_imageDataOffset = $value;
338  }
339  break;
341  if($valueCount>1) {
342  $format = ($this->_endianType == Zend_Pdf_Resource_Image_Tiff::TIFF_ENDIAN_LITTLE)?'V*':'N*';
343  $fp = ftell($imageFile);
344  fseek($imageFile, $refOffset, SEEK_SET);
345  $stripByteCountsBytes = fread($imageFile, $fieldLength);
346  $this->_imageDataLength = unpack($format, $stripByteCountsBytes);
347  fseek($imageFile, $fp, SEEK_SET);
348  } else {
349  $this->_imageDataLength = $value;
350  }
351  break;
352  default:
353  //For debugging. It should be harmless to ignore unknown tags, though there is some good info in them.
354  //echo "Unknown tag detected: ". $tag . " value: ". $value;
355  }
356  }
357  $ifdOffset = $this->unpackBytes(Zend_Pdf_Resource_Image_Tiff::UNPACK_TYPE_LONG, fread($imageFile, 4));
358  }
359 
360  if(!isset($this->_imageDataOffset) || !isset($this->_imageDataLength)) {
361  #require_once 'Zend/Pdf/Exception.php';
362  throw new Zend_Pdf_Exception("TIFF: The image processed did not contain image data as expected.");
363  }
364 
365  $imageDataBytes = '';
366  if(is_array($this->_imageDataOffset)) {
367  if(!is_array($this->_imageDataLength)) {
368  #require_once 'Zend/Pdf/Exception.php';
369  throw new Zend_Pdf_Exception("TIFF: The image contained multiple data offsets but not multiple data lengths. Tiff may be corrupt.");
370  }
371  foreach($this->_imageDataOffset as $idx => $offset) {
372  fseek($imageFile, $this->_imageDataOffset[$idx], SEEK_SET);
373  $imageDataBytes .= fread($imageFile, $this->_imageDataLength[$idx]);
374  }
375  } else {
376  fseek($imageFile, $this->_imageDataOffset, SEEK_SET);
377  $imageDataBytes = fread($imageFile, $this->_imageDataLength);
378  }
379  if($imageDataBytes === '') {
380  #require_once 'Zend/Pdf/Exception.php';
381  throw new Zend_Pdf_Exception("TIFF: No data. Image Corruption");
382  }
383 
384  fclose($imageFile);
385 
386  parent::__construct();
387 
388  $imageDictionary = $this->_resource->dictionary;
389  if(!isset($this->_width) || !isset($this->_width)) {
390  #require_once 'Zend/Pdf/Exception.php';
391  throw new Zend_Pdf_Exception("Problem reading tiff file. Tiff is probably corrupt.");
392  }
393 
394  $this->_imageProperties = array();
395  $this->_imageProperties['bitDepth'] = $this->_bitsPerSample;
396  $this->_imageProperties['fileSize'] = $this->_fileSize;
397  $this->_imageProperties['TIFFendianType'] = $this->_endianType;
398  $this->_imageProperties['TIFFcompressionType'] = $this->_compression;
399  $this->_imageProperties['TIFFwhiteIsZero'] = $this->_whiteIsZero;
400  $this->_imageProperties['TIFFblackIsZero'] = $this->_blackIsZero;
401  $this->_imageProperties['TIFFcolorCode'] = $this->_colorCode;
402  $this->_imageProperties['TIFFimageDataOffset'] = $this->_imageDataOffset;
403  $this->_imageProperties['TIFFimageDataLength'] = $this->_imageDataLength;
404  $this->_imageProperties['PDFfilter'] = $this->_filter;
405  $this->_imageProperties['PDFcolorSpace'] = $this->_colorSpace;
406 
407  $imageDictionary->Width = new Zend_Pdf_Element_Numeric($this->_width);
408  if($this->_whiteIsZero === true) {
409  $imageDictionary->Decode = new Zend_Pdf_Element_Array(array(new Zend_Pdf_Element_Numeric(1), new Zend_Pdf_Element_Numeric(0)));
410  }
411  $imageDictionary->Height = new Zend_Pdf_Element_Numeric($this->_height);
412  $imageDictionary->ColorSpace = new Zend_Pdf_Element_Name($this->_colorSpace);
413  $imageDictionary->BitsPerComponent = new Zend_Pdf_Element_Numeric($this->_bitsPerSample);
414  if(isset($this->_filter) && $this->_filter != 'None') {
415  $imageDictionary->Filter = new Zend_Pdf_Element_Name($this->_filter);
416  }
417 
418  $this->_resource->value = $imageDataBytes;
419  $this->_resource->skipFilters();
420  }
424  public function getPixelWidth() {
425  return $this->_width;
426  }
427 
431  public function getPixelHeight() {
432  return $this->_height;
433  }
434 
438  public function getProperties() {
440  }
441 }
442 
const TIFF_PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO
Definition: Tiff.php:65
const TIFF_TAG_STRIP_BYTE_COUNTS
Definition: Tiff.php:53
const TIFF_COMPRESSION_FLATE_OBSOLETE_CODE
Definition: Tiff.php:62
const TIFF_PHOTOMETRIC_INTERPRETATION_YCBCR
Definition: Tiff.php:70
__construct($imageFileName)
Definition: Tiff.php:140
const TIFF_PHOTOMETRIC_INTERPRETATION_CMYK
Definition: Tiff.php:69
$type
Definition: item.phtml:13
unpackBytes($type, $bytes)
Definition: Tiff.php:105
$value
Definition: gender.phtml:16
$format
Definition: list.phtml:12
const TIFF_TAG_SAMPLES_PER_PIXEL
Definition: Tiff.php:52
const TIFF_COMPRESSION_UNCOMPRESSED
Definition: Tiff.php:55
const TIFF_COMPRESSION_GROUP_3_FAX
Definition: Tiff.php:57
const TIFF_PHOTOMETRIC_INTERPRETATION_RGB
Definition: Tiff.php:67
const TIFF_PHOTOMETRIC_INTERPRETATION_RGB_INDEXED
Definition: Tiff.php:68
const TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO
Definition: Tiff.php:66
const TIFF_COMPRESSION_GROUP_4_FAX
Definition: Tiff.php:58
const TIFF_TAG_PHOTOMETRIC_INTERPRETATION
Definition: Tiff.php:50
const TIFF_PHOTOMETRIC_INTERPRETATION_CIELAB
Definition: Tiff.php:71