module.graphic.tiff.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. // also https://github.com/JamesHeinrich/getID3 //
  7. /////////////////////////////////////////////////////////////////
  8. // See readme.txt for more details //
  9. /////////////////////////////////////////////////////////////////
  10. // //
  11. // module.archive.tiff.php //
  12. // module for analyzing TIFF files //
  13. // dependencies: NONE //
  14. // ///
  15. /////////////////////////////////////////////////////////////////
  16. class getid3_tiff extends getid3_handler
  17. {
  18. public function Analyze() {
  19. $info = &$this->getid3->info;
  20. $this->fseek($info['avdataoffset']);
  21. $TIFFheader = $this->fread(4);
  22. switch (substr($TIFFheader, 0, 2)) {
  23. case 'II':
  24. $info['tiff']['byte_order'] = 'Intel';
  25. break;
  26. case 'MM':
  27. $info['tiff']['byte_order'] = 'Motorola';
  28. break;
  29. default:
  30. $info['error'][] = 'Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset'];
  31. return false;
  32. break;
  33. }
  34. $info['fileformat'] = 'tiff';
  35. $info['video']['dataformat'] = 'tiff';
  36. $info['video']['lossless'] = true;
  37. $info['tiff']['ifd'] = array();
  38. $CurrentIFD = array();
  39. $FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
  40. $nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
  41. while ($nextIFDoffset > 0) {
  42. $CurrentIFD['offset'] = $nextIFDoffset;
  43. $this->fseek($info['avdataoffset'] + $nextIFDoffset);
  44. $CurrentIFD['fieldcount'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
  45. for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
  46. $CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
  47. $CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
  48. $CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
  49. $CurrentIFD['fields'][$i]['raw']['offset'] = $this->fread(4);
  50. switch ($CurrentIFD['fields'][$i]['raw']['type']) {
  51. case 1: // BYTE An 8-bit unsigned integer.
  52. if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
  53. $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $info['tiff']['byte_order']);
  54. } else {
  55. $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
  56. }
  57. break;
  58. case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null.
  59. if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
  60. $CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3);
  61. } else {
  62. $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
  63. }
  64. break;
  65. case 3: // SHORT A 16-bit (2-byte) unsigned integer.
  66. if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
  67. $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $info['tiff']['byte_order']);
  68. } else {
  69. $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
  70. }
  71. break;
  72. case 4: // LONG A 32-bit (4-byte) unsigned integer.
  73. if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) {
  74. $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
  75. } else {
  76. $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
  77. }
  78. break;
  79. case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator.
  80. break;
  81. }
  82. }
  83. $info['tiff']['ifd'][] = $CurrentIFD;
  84. $CurrentIFD = array();
  85. $nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
  86. }
  87. foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) {
  88. foreach ($IFDarray['fields'] as $key => $fieldarray) {
  89. switch ($fieldarray['raw']['tag']) {
  90. case 256: // ImageWidth
  91. case 257: // ImageLength
  92. case 258: // BitsPerSample
  93. case 259: // Compression
  94. if (!isset($fieldarray['value'])) {
  95. $this->fseek($fieldarray['offset']);
  96. $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
  97. }
  98. break;
  99. case 270: // ImageDescription
  100. case 271: // Make
  101. case 272: // Model
  102. case 305: // Software
  103. case 306: // DateTime
  104. case 315: // Artist
  105. case 316: // HostComputer
  106. if (isset($fieldarray['value'])) {
  107. $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value'];
  108. } else {
  109. $this->fseek($fieldarray['offset']);
  110. $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
  111. }
  112. break;
  113. }
  114. switch ($fieldarray['raw']['tag']) {
  115. case 256: // ImageWidth
  116. $info['video']['resolution_x'] = $fieldarray['value'];
  117. break;
  118. case 257: // ImageLength
  119. $info['video']['resolution_y'] = $fieldarray['value'];
  120. break;
  121. case 258: // BitsPerSample
  122. if (isset($fieldarray['value'])) {
  123. $info['video']['bits_per_sample'] = $fieldarray['value'];
  124. } else {
  125. $info['video']['bits_per_sample'] = 0;
  126. for ($i = 0; $i < $fieldarray['raw']['length']; $i++) {
  127. $info['video']['bits_per_sample'] += $this->TIFFendian2Int(substr($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'], $i * $FieldTypeByteLength[$fieldarray['raw']['type']], $FieldTypeByteLength[$fieldarray['raw']['type']]), $info['tiff']['byte_order']);
  128. }
  129. }
  130. break;
  131. case 259: // Compression
  132. $info['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']);
  133. break;
  134. case 270: // ImageDescription
  135. case 271: // Make
  136. case 272: // Model
  137. case 305: // Software
  138. case 306: // DateTime
  139. case 315: // Artist
  140. case 316: // HostComputer
  141. $TIFFcommentName = $this->TIFFcommentName($fieldarray['raw']['tag']);
  142. if (isset($info['tiff']['comments'][$TIFFcommentName])) {
  143. $info['tiff']['comments'][$TIFFcommentName][] = $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'];
  144. } else {
  145. $info['tiff']['comments'][$TIFFcommentName] = array($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']);
  146. }
  147. break;
  148. default:
  149. break;
  150. }
  151. }
  152. }
  153. return true;
  154. }
  155. public function TIFFendian2Int($bytestring, $byteorder) {
  156. if ($byteorder == 'Intel') {
  157. return getid3_lib::LittleEndian2Int($bytestring);
  158. } elseif ($byteorder == 'Motorola') {
  159. return getid3_lib::BigEndian2Int($bytestring);
  160. }
  161. return false;
  162. }
  163. public function TIFFcompressionMethod($id) {
  164. static $TIFFcompressionMethod = array();
  165. if (empty($TIFFcompressionMethod)) {
  166. $TIFFcompressionMethod = array(
  167. 1 => 'Uncompressed',
  168. 2 => 'Huffman',
  169. 3 => 'Fax - CCITT 3',
  170. 5 => 'LZW',
  171. 32773 => 'PackBits',
  172. );
  173. }
  174. return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
  175. }
  176. public function TIFFcommentName($id) {
  177. static $TIFFcommentName = array();
  178. if (empty($TIFFcommentName)) {
  179. $TIFFcommentName = array(
  180. 270 => 'imagedescription',
  181. 271 => 'make',
  182. 272 => 'model',
  183. 305 => 'software',
  184. 306 => 'datetime',
  185. 315 => 'artist',
  186. 316 => 'hostcomputer',
  187. );
  188. }
  189. return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');
  190. }
  191. }