File indexing completed on 2024-05-12 05:58:15

0001 <?php
0002 /////////////////////////////////////////////////////////////////
0003 /// getID3() by James Heinrich <info@getid3.org>               //
0004 //  available at http://getid3.sourceforge.net                 //
0005 //            or http://www.getid3.org                         //
0006 //          also https://github.com/JamesHeinrich/getID3       //
0007 /////////////////////////////////////////////////////////////////
0008 // See readme.txt for more details                             //
0009 /////////////////////////////////////////////////////////////////
0010 //                                                             //
0011 // module.archive.tiff.php                                     //
0012 // module for analyzing TIFF files                             //
0013 // dependencies: NONE                                          //
0014 //                                                            ///
0015 /////////////////////////////////////////////////////////////////
0016 
0017 
0018 class getid3_tiff extends getid3_handler
0019 {
0020 
0021   public function Analyze() {
0022     $info = &$this->getid3->info;
0023 
0024     $this->fseek($info['avdataoffset']);
0025     $TIFFheader = $this->fread(4);
0026 
0027     switch (substr($TIFFheader, 0, 2)) {
0028       case 'II':
0029         $info['tiff']['byte_order'] = 'Intel';
0030         break;
0031       case 'MM':
0032         $info['tiff']['byte_order'] = 'Motorola';
0033         break;
0034       default:
0035         $info['error'][] = 'Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset'];
0036         return false;
0037         break;
0038     }
0039 
0040     $info['fileformat']          = 'tiff';
0041     $info['video']['dataformat'] = 'tiff';
0042     $info['video']['lossless']   = true;
0043     $info['tiff']['ifd']         = array();
0044     $CurrentIFD                          = array();
0045 
0046     $FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
0047 
0048     $nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
0049 
0050     while ($nextIFDoffset > 0) {
0051 
0052       $CurrentIFD['offset'] = $nextIFDoffset;
0053 
0054       $this->fseek($info['avdataoffset'] + $nextIFDoffset);
0055       $CurrentIFD['fieldcount'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
0056 
0057       for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
0058         $CurrentIFD['fields'][$i]['raw']['tag']    = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
0059         $CurrentIFD['fields'][$i]['raw']['type']   = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
0060         $CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
0061         $CurrentIFD['fields'][$i]['raw']['offset'] =                       $this->fread(4);
0062 
0063         switch ($CurrentIFD['fields'][$i]['raw']['type']) {
0064           case 1: // BYTE  An 8-bit unsigned integer.
0065             if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
0066               $CurrentIFD['fields'][$i]['value']  = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $info['tiff']['byte_order']);
0067             } else {
0068               $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
0069             }
0070             break;
0071 
0072           case 2: // ASCII 8-bit bytes  that store ASCII codes; the last byte must be null.
0073             if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
0074               $CurrentIFD['fields'][$i]['value']  = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3);
0075             } else {
0076               $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
0077             }
0078             break;
0079 
0080           case 3: // SHORT A 16-bit (2-byte) unsigned integer.
0081             if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
0082               $CurrentIFD['fields'][$i]['value']  = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $info['tiff']['byte_order']);
0083             } else {
0084               $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
0085             }
0086             break;
0087 
0088           case 4: // LONG  A 32-bit (4-byte) unsigned integer.
0089             if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) {
0090               $CurrentIFD['fields'][$i]['value']  = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
0091             } else {
0092               $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
0093             }
0094             break;
0095 
0096           case 5: // RATIONAL   Two LONG_s:  the first represents the numerator of a fraction, the second the denominator.
0097             break;
0098         }
0099       }
0100 
0101       $info['tiff']['ifd'][] = $CurrentIFD;
0102       $CurrentIFD = array();
0103       $nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
0104 
0105     }
0106 
0107     foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) {
0108       foreach ($IFDarray['fields'] as $key => $fieldarray) {
0109         switch ($fieldarray['raw']['tag']) {
0110           case 256: // ImageWidth
0111           case 257: // ImageLength
0112           case 258: // BitsPerSample
0113           case 259: // Compression
0114             if (!isset($fieldarray['value'])) {
0115               $this->fseek($fieldarray['offset']);
0116               $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
0117 
0118             }
0119             break;
0120 
0121           case 270: // ImageDescription
0122           case 271: // Make
0123           case 272: // Model
0124           case 305: // Software
0125           case 306: // DateTime
0126           case 315: // Artist
0127           case 316: // HostComputer
0128             if (isset($fieldarray['value'])) {
0129               $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value'];
0130             } else {
0131               $this->fseek($fieldarray['offset']);
0132               $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
0133 
0134             }
0135             break;
0136         }
0137         switch ($fieldarray['raw']['tag']) {
0138           case 256: // ImageWidth
0139             $info['video']['resolution_x'] = $fieldarray['value'];
0140             break;
0141 
0142           case 257: // ImageLength
0143             $info['video']['resolution_y'] = $fieldarray['value'];
0144             break;
0145 
0146           case 258: // BitsPerSample
0147             if (isset($fieldarray['value'])) {
0148               $info['video']['bits_per_sample'] = $fieldarray['value'];
0149             } else {
0150               $info['video']['bits_per_sample'] = 0;
0151               for ($i = 0; $i < $fieldarray['raw']['length']; $i++) {
0152                 $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']);
0153               }
0154             }
0155             break;
0156 
0157           case 259: // Compression
0158             $info['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']);
0159             break;
0160 
0161           case 270: // ImageDescription
0162           case 271: // Make
0163           case 272: // Model
0164           case 305: // Software
0165           case 306: // DateTime
0166           case 315: // Artist
0167           case 316: // HostComputer
0168             $TIFFcommentName = $this->TIFFcommentName($fieldarray['raw']['tag']);
0169             if (isset($info['tiff']['comments'][$TIFFcommentName])) {
0170               $info['tiff']['comments'][$TIFFcommentName][] =       $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'];
0171             } else {
0172               $info['tiff']['comments'][$TIFFcommentName]   = array($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']);
0173             }
0174             break;
0175 
0176           default:
0177             break;
0178         }
0179       }
0180     }
0181 
0182     return true;
0183   }
0184 
0185 
0186   public function TIFFendian2Int($bytestring, $byteorder) {
0187     if ($byteorder == 'Intel') {
0188       return getid3_lib::LittleEndian2Int($bytestring);
0189     } elseif ($byteorder == 'Motorola') {
0190       return getid3_lib::BigEndian2Int($bytestring);
0191     }
0192     return false;
0193   }
0194 
0195   public function TIFFcompressionMethod($id) {
0196     static $TIFFcompressionMethod = array();
0197     if (empty($TIFFcompressionMethod)) {
0198       $TIFFcompressionMethod = array(
0199         1     => 'Uncompressed',
0200         2     => 'Huffman',
0201         3     => 'Fax - CCITT 3',
0202         5     => 'LZW',
0203         32773 => 'PackBits',
0204       );
0205     }
0206     return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
0207   }
0208 
0209   public function TIFFcommentName($id) {
0210     static $TIFFcommentName = array();
0211     if (empty($TIFFcommentName)) {
0212       $TIFFcommentName = array(
0213         270 => 'imagedescription',
0214         271 => 'make',
0215         272 => 'model',
0216         305 => 'software',
0217         306 => 'datetime',
0218         315 => 'artist',
0219         316 => 'hostcomputer',
0220       );
0221     }
0222     return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');
0223   }
0224 
0225 }