<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <[email protected]> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.tiff.php //
// module for analyzing TIFF files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_tiff extends getid3_handler
{
function Analyze() {
$info = &$this->getid3->info;
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
$TIFFheader = fread($this->getid3->fp, 4);
switch (substr($TIFFheader, 0, 2)) {
case 'II':
$info['tiff']['byte_order'] = 'Intel';
break;
case 'MM':
$info['tiff']['byte_order'] = 'Motorola';
break;
default:
$info['error'][] = 'Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset'];
return false;
break;
}
$info['fileformat'] = 'tiff';
$info['video']['dataformat'] = 'tiff';
$info['video']['lossless'] = true;
$info['tiff']['ifd'] = array();
$CurrentIFD = array();
$FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
$nextIFDoffset = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']);
while ($nextIFDoffset > 0) {
$CurrentIFD['offset'] = $nextIFDoffset;
fseek($this->getid3->fp, $info['avdataoffset'] + $nextIFDoffset, SEEK_SET);
$CurrentIFD['fieldcount'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']);
for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
$CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']);
$CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']);
$CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']);
$CurrentIFD['fields'][$i]['raw']['offset'] = fread($this->getid3->fp, 4);
switch ($CurrentIFD['fields'][$i]['raw']['type']) {
case 1: // BYTE An 8-bit unsigned integer.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $info['tiff']['byte_order']);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
}
break;
case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
$CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
}
break;
case 3: // SHORT A 16-bit (2-byte) unsigned integer.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $info['tiff']['byte_order']);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
}
break;
case 4: // LONG A 32-bit (4-byte) unsigned integer.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) {
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
}
break;
case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator.
break;
}
}
$info['tiff']['ifd'][] = $CurrentIFD;
$CurrentIFD = array();
$nextIFDoffset = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']);
}
foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) {
foreach ($IFDarray['fields'] as $key => $fieldarray) {
switch ($fieldarray['raw']['tag']) {
case 256: // ImageWidth
case 257: // ImageLength
case 258: // BitsPerSample
case 259: // Compression
if (!isset($fieldarray['value'])) {
fseek($this->getid3->fp, $fieldarray['offset'], SEEK_SET);
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($this->getid3->fp, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
}
break;
case 270: // ImageDescription
case 271: // Make
case 272: // Model
case 305: // Software
case 306: // DateTime
case 315: // Artist
case 316: // HostComputer
if (isset($fieldarray['value'])) {
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value'];
} else {
fseek($this->getid3->fp, $fieldarray['offset'], SEEK_SET);
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($this->getid3->fp, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
}
break;
}
switch ($fieldarray['raw']['tag']) {
case 256: // ImageWidth
$info['video']['resolution_x'] = $fieldarray['value'];
break;
case 257: // ImageLength
$info['video']['resolution_y'] = $fieldarray['value'];
break;
case 258: // BitsPerSample
if (isset($fieldarray['value'])) {
$info['video']['bits_per_sample'] = $fieldarray['value'];
} else {
$info['video']['bits_per_sample'] = 0;
for ($i = 0; $i < $fieldarray['raw']['length']; $i++) {
$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']);
}
}
break;
case 259: // Compression
$info['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']);
break;
case 270: // ImageDescription
case 271: // Make
case 272: // Model
case 305: // Software
case 306: // DateTime
case 315: // Artist
case 316: // HostComputer
$TIFFcommentName = $this->TIFFcommentName($fieldarray['raw']['tag']);
if (isset($info['tiff']['comments'][$TIFFcommentName])) {
$info['tiff']['comments'][$TIFFcommentName][] = $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'];
} else {
$info['tiff']['comments'][$TIFFcommentName] = array($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']);
}
break;
default:
break;
}
}
}
return true;
}
function TIFFendian2Int($bytestring, $byteorder) {
if ($byteorder == 'Intel') {
return getid3_lib::LittleEndian2Int($bytestring);
} elseif ($byteorder == 'Motorola') {
return getid3_lib::BigEndian2Int($bytestring);
}
return false;
}
function TIFFcompressionMethod($id) {
static $TIFFcompressionMethod = array();
if (empty($TIFFcompressionMethod)) {
$TIFFcompressionMethod = array(
1 => 'Uncompressed',
2 => 'Huffman',
3 => 'Fax - CCITT 3',
5 => 'LZW',
32773 => 'PackBits',
);
}
return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
}
function TIFFcommentName($id) {
static $TIFFcommentName = array();
if (empty($TIFFcommentName)) {
$TIFFcommentName = array(
270 => 'imagedescription',
271 => 'make',
272 => 'model',
305 => 'software',
306 => 'datetime',
315 => 'artist',
316 => 'hostcomputer',
);
}
return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');
}
}
?>