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 /////////////////////////////////////////////////////////////////
11 // module.archive.tiff.php //
12 // module for analyzing TIFF files //
13 // dependencies: NONE //
15 /////////////////////////////////////////////////////////////////
18 class getid3_tiff extends getid3_handler
21 public function Analyze() {
22 $info = &$this->getid3->info;
24 $this->fseek($info['avdataoffset']);
25 $TIFFheader = $this->fread(4);
27 switch (substr($TIFFheader, 0, 2)) {
29 $info['tiff']['byte_order'] = 'Intel';
32 $info['tiff']['byte_order'] = 'Motorola';
35 $this->error('Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset']);
40 $info['fileformat'] = 'tiff';
41 $info['video']['dataformat'] = 'tiff';
42 $info['video']['lossless'] = true;
43 $info['tiff']['ifd'] = array();
44 $CurrentIFD = array();
46 $FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
48 $nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
50 while ($nextIFDoffset > 0) {
52 $CurrentIFD['offset'] = $nextIFDoffset;
54 $this->fseek($info['avdataoffset'] + $nextIFDoffset);
55 $CurrentIFD['fieldcount'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
57 for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
58 $CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
59 $CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
60 $CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
61 $CurrentIFD['fields'][$i]['raw']['offset'] = $this->fread(4);
63 switch ($CurrentIFD['fields'][$i]['raw']['type']) {
64 case 1: // BYTE An 8-bit unsigned integer.
65 if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
66 $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $info['tiff']['byte_order']);
68 $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
72 case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null.
73 if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
74 $CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3);
76 $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
80 case 3: // SHORT A 16-bit (2-byte) unsigned integer.
81 if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
82 $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $info['tiff']['byte_order']);
84 $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
88 case 4: // LONG A 32-bit (4-byte) unsigned integer.
89 if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) {
90 $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
92 $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
96 case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator.
101 $info['tiff']['ifd'][] = $CurrentIFD;
102 $CurrentIFD = array();
103 $nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
107 foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) {
108 foreach ($IFDarray['fields'] as $key => $fieldarray) {
109 switch ($fieldarray['raw']['tag']) {
110 case 256: // ImageWidth
111 case 257: // ImageLength
112 case 258: // BitsPerSample
113 case 259: // Compression
114 if (!isset($fieldarray['value'])) {
115 $this->fseek($fieldarray['offset']);
116 $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
121 case 270: // ImageDescription
124 case 305: // Software
125 case 306: // DateTime
127 case 316: // HostComputer
128 if (isset($fieldarray['value'])) {
129 $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value'];
131 $this->fseek($fieldarray['offset']);
132 $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
137 switch ($fieldarray['raw']['tag']) {
138 case 256: // ImageWidth
139 $info['video']['resolution_x'] = $fieldarray['value'];
142 case 257: // ImageLength
143 $info['video']['resolution_y'] = $fieldarray['value'];
146 case 258: // BitsPerSample
147 if (isset($fieldarray['value'])) {
148 $info['video']['bits_per_sample'] = $fieldarray['value'];
150 $info['video']['bits_per_sample'] = 0;
151 for ($i = 0; $i < $fieldarray['raw']['length']; $i++) {
152 $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']);
157 case 259: // Compression
158 $info['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']);
161 case 270: // ImageDescription
164 case 305: // Software
165 case 306: // DateTime
167 case 316: // HostComputer
168 $TIFFcommentName = $this->TIFFcommentName($fieldarray['raw']['tag']);
169 if (isset($info['tiff']['comments'][$TIFFcommentName])) {
170 $info['tiff']['comments'][$TIFFcommentName][] = $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'];
172 $info['tiff']['comments'][$TIFFcommentName] = array($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']);
186 public function TIFFendian2Int($bytestring, $byteorder) {
187 if ($byteorder == 'Intel') {
188 return getid3_lib::LittleEndian2Int($bytestring);
189 } elseif ($byteorder == 'Motorola') {
190 return getid3_lib::BigEndian2Int($bytestring);
195 public function TIFFcompressionMethod($id) {
196 static $TIFFcompressionMethod = array();
197 if (empty($TIFFcompressionMethod)) {
198 $TIFFcompressionMethod = array(
201 3 => 'Fax - CCITT 3',
206 return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
209 public function TIFFcommentName($id) {
210 static $TIFFcommentName = array();
211 if (empty($TIFFcommentName)) {
212 $TIFFcommentName = array(
213 270 => 'imagedescription',
219 316 => 'hostcomputer',
222 return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');