123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
<?php
if (!defined('GETID3_INCLUDEPATH')) {
exit;
}
class getid3_tiff extends getid3_handler
{
public function Analyze() {
$info = &$this->getid3->info;
$this->fseek($info['avdataoffset']);
$TIFFheader = $this->fread(4);
switch (substr($TIFFheader, 0, 2)) {
case 'II':
$info['tiff']['byte_order'] = 'Intel';
break;
case 'MM':
$info['tiff']['byte_order'] = 'Motorola';
break;
default:
$this->error('Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset']);
return false;
}
$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($this->fread(4), $info['tiff']['byte_order']);
while ($nextIFDoffset > 0) {
$CurrentIFD['offset'] = $nextIFDoffset;
$this->fseek($info['avdataoffset'] + $nextIFDoffset);
$CurrentIFD['fieldcount'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
$CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
$CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
$CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
$CurrentIFD['fields'][$i]['raw']['valoff'] = $this->fread(4);
$CurrentIFD['fields'][$i]['raw']['tag_name'] = $this->TIFFcommentName($CurrentIFD['fields'][$i]['raw']['tag']);
switch ($CurrentIFD['fields'][$i]['raw']['type']) {
case 1:
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['valoff'], 0, 1), $info['tiff']['byte_order']);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
}
break;
case 2:
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
$CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['valoff'], 3);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
}
break;
case 3:
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['valoff'], 0, 2), $info['tiff']['byte_order']);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
}
break;
case 4:
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
}
break;
case 5:
case 7:
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
break;
case 6:
case 8:
case 9:
case 10:
case 11:
case 12:
default:
$this->warning('unhandled IFD field type '.$CurrentIFD['fields'][$i]['raw']['type'].' for IFD entry '.$i);
break;
}
}
$info['tiff']['ifd'][] = $CurrentIFD;
$CurrentIFD = array();
$nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
}
foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) {
if(!isset($IFDarray['fields'])) {
continue;
}
foreach ($IFDarray['fields'] as $key => $fieldarray) {
switch ($fieldarray['raw']['tag']) {
case 256:
case 257:
case 258:
case 259:
if (!isset($fieldarray['value'])) {
$this->fseek($fieldarray['offset']);
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
}
break;
case 270:
case 271:
case 272:
case 305:
case 306:
case 315:
case 316:
if (isset($fieldarray['value'])) {
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value'];
} else {
$this->fseek($fieldarray['offset']);
$info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
}
break;
case 700:
$XMPmagic = '<?xpacket';
$this->fseek($fieldarray['offset']);
$xmpkey = (isset($info['tiff']['XMP']) ? count($info['tiff']['XMP']) : 0);
$info['tiff']['XMP'][$xmpkey]['raw'] = $this->fread($fieldarray['raw']['length']);
if (substr($info['tiff']['XMP'][$xmpkey]['raw'], 0, strlen($XMPmagic)) != $XMPmagic) {
$this->warning('did not find expected XMP data at offset '.$fieldarray['offset']);
unset($info['tiff']['XMP'][$xmpkey]['raw']);
}
break;
}
switch ($fieldarray['raw']['tag']) {
case 256:
$info['video']['resolution_x'] = $fieldarray['value'];
break;
case 257:
$info['video']['resolution_y'] = $fieldarray['value'];
break;
case 258:
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:
$info['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']);
break;
case 270:
case 271:
case 272:
case 305:
case 306:
case 315:
case 316:
$TIFFcommentName = strtolower($fieldarray['raw']['tag_name']);
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;
}
public function TIFFendian2Int($bytestring, $byteorder) {
if ($byteorder == 'Intel') {
return getid3_lib::LittleEndian2Int($bytestring);
} elseif ($byteorder == 'Motorola') {
return getid3_lib::BigEndian2Int($bytestring);
}
return false;
}
public function TIFFcompressionMethod($id) {
static $TIFFcompressionMethod = array();
if (empty($TIFFcompressionMethod)) {
$TIFFcompressionMethod = array(
0x0001 => 'Uncompressed',
0x0002 => 'Huffman',
0x0003 => 'CCITT T.4',
0x0004 => 'CCITT T.6',
0x0005 => 'LZW',
0x0006 => 'JPEG-old',
0x0007 => 'JPEG',
0x0008 => 'deflate',
0x0009 => 'JBIG ITU-T T.85',
0x000A => 'JBIG ITU-T T.43',
0x7FFE => 'NeXT RLE 2-bit',
0x8005 => 'PackBits',
0x8029 => 'ThunderScan RLE 4-bit',
0x807F => 'RasterPadding',
0x8080 => 'RLE-LW',
0x8081 => 'RLE-CT',
0x8082 => 'RLE-BL',
0x80B2 => 'deflate-PK',
0x80B3 => 'Kodak-DCS',
0x8765 => 'JBIG',
0x8798 => 'JPEG2000',
0x8799 => 'Nikon NEF',
0x879B => 'JBIG2',
);
}
return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
}
public function TIFFcommentName($id) {
static $TIFFcommentName = array();
if (empty($TIFFcommentName)) {
$TIFFcommentName = array(
254 => 'NewSubfileType',
255 => 'SubfileType',
256 => 'ImageWidth',
257 => 'ImageLength',
258 => 'BitsPerSample',
259 => 'Compression',
262 => 'PhotometricInterpretation',
263 => 'Threshholding',
264 => 'CellWidth',
265 => 'CellLength',
266 => 'FillOrder',
269 => 'DocumentName',
270 => 'ImageDescription',
271 => 'Make',
272 => 'Model',
273 => 'StripOffsets',
274 => 'Orientation',
277 => 'SamplesPerPixel',
278 => 'RowsPerStrip',
279 => 'StripByteCounts',
280 => 'MinSampleValue',
281 => 'MaxSampleValue',
282 => 'XResolution',
283 => 'YResolution',
284 => 'PlanarConfiguration',
285 => 'PageName',
286 => 'XPosition',
287 => 'YPosition',
288 => 'FreeOffsets',
289 => 'FreeByteCounts',
290 => 'GrayResponseUnit',
291 => 'GrayResponseCurve',
292 => 'T4Options',
293 => 'T6Options',
296 => 'ResolutionUnit',
297 => 'PageNumber',
301 => 'TransferFunction',
305 => 'Software',
306 => 'DateTime',
315 => 'Artist',
316 => 'HostComputer',
317 => 'Predictor',
318 => 'WhitePoint',
319 => 'PrimaryChromaticities',
320 => 'ColorMap',
321 => 'HalftoneHints',
322 => 'TileWidth',
323 => 'TileLength',
324 => 'TileOffsets',
325 => 'TileByteCounts',
326 => 'BadFaxLines',
327 => 'CleanFaxData',
328 => 'ConsecutiveBadFaxLines',
330 => 'SubIFDs',
332 => 'InkSet',
333 => 'InkNames',
334 => 'NumberOfInks',
336 => 'DotRange',
337 => 'TargetPrinter',
338 => 'ExtraSamples',
339 => 'SampleFormat',
340 => 'SMinSampleValue',
341 => 'SMaxSampleValue',
342 => 'TransferRange',
343 => 'ClipPath',
344 => 'XClipPathUnits',
345 => 'YClipPathUnits',
346 => 'Indexed',
347 => 'JPEGTables',
351 => 'OPIProxy',
400 => 'GlobalParametersIFD',
401 => 'ProfileType',
402 => 'FaxProfile',
403 => 'CodingMethods',
404 => 'VersionYear',
405 => 'ModeNumber',
433 => 'Decode',
434 => 'DefaultImageColor',
512 => 'JPEGProc',
513 => 'JPEGInterchangeFormat',
514 => 'JPEGInterchangeFormatLngth',
515 => 'JPEGRestartInterval',
517 => 'JPEGLosslessPredictors',
518 => 'JPEGPointTransforms',
519 => 'JPEGQTables',
520 => 'JPEGDCTables',
521 => 'JPEGACTables',
529 => 'YCbCrCoefficients',
530 => 'YCbCrSubSampling',
531 => 'YCbCrPositioning',
532 => 'ReferenceBlackWhite',
559 => 'StripRowCounts',
700 => 'XMP',
32781 => 'ImageID',
33432 => 'Copyright',
34732 => 'ImageLayer',
32932 => 'Wang Annotation',
33445 => 'MD FileTag',
33446 => 'MD ScalePixel',
33447 => 'MD ColorTable',
33448 => 'MD LabName',
33449 => 'MD SampleInfo',
33450 => 'MD PrepDate',
33451 => 'MD PrepTime',
33452 => 'MD FileUnits',
33550 => 'ModelPixelScaleTag',
33723 => 'IPTC',
33918 => 'INGR Packet Data Tag',
33919 => 'INGR Flag Registers',
33920 => 'IrasB Transformation Matrix',
33922 => 'ModelTiepointTag',
34264 => 'ModelTransformationTag',
34377 => 'Photoshop',
34665 => 'Exif IFD',
34675 => 'ICC Profile',
34735 => 'GeoKeyDirectoryTag',
34736 => 'GeoDoubleParamsTag',
34737 => 'GeoAsciiParamsTag',
34853 => 'GPS IFD',
34908 => 'HylaFAX FaxRecvParams',
34909 => 'HylaFAX FaxSubAddress',
34910 => 'HylaFAX FaxRecvTime',
37724 => 'ImageSourceData',
40965 => 'Interoperability IFD',
42112 => 'GDAL_METADATA',
42113 => 'GDAL_NODATA',
50215 => 'Oce Scanjob Description',
50216 => 'Oce Application Selector',
50217 => 'Oce Identification Number',
50218 => 'Oce ImageLogic Characteristics',
50706 => 'DNGVersion',
50707 => 'DNGBackwardVersion',
50708 => 'UniqueCameraModel',
50709 => 'LocalizedCameraModel',
50710 => 'CFAPlaneColor',
50711 => 'CFALayout',
50712 => 'LinearizationTable',
50713 => 'BlackLevelRepeatDim',
50714 => 'BlackLevel',
50715 => 'BlackLevelDeltaH',
50716 => 'BlackLevelDeltaV',
50717 => 'WhiteLevel',
50718 => 'DefaultScale',
50719 => 'DefaultCropOrigin',
50720 => 'DefaultCropSize',
50721 => 'ColorMatrix1',
50722 => 'ColorMatrix2',
50723 => 'CameraCalibration1',
50724 => 'CameraCalibration2',
50725 => 'ReductionMatrix1',
50726 => 'ReductionMatrix2',
50727 => 'AnalogBalance',
50728 => 'AsShotNeutral',
50729 => 'AsShotWhiteXY',
50730 => 'BaselineExposure',
50731 => 'BaselineNoise',
50732 => 'BaselineSharpness',
50733 => 'BayerGreenSplit',
50734 => 'LinearResponseLimit',
50735 => 'CameraSerialNumber',
50736 => 'LensInfo',
50737 => 'ChromaBlurRadius',
50738 => 'AntiAliasStrength',
50740 => 'DNGPrivateData',
50741 => 'MakerNoteSafety',
50778 => 'CalibrationIlluminant1',
50779 => 'CalibrationIlluminant2',
50780 => 'BestQualityScale',
50784 => 'Alias Layer Metadata',
50908 => 'TIFF_RSID',
50909 => 'GEO_METADATA',
33434 => 'ExposureTime',
33437 => 'FNumber',
34850 => 'ExposureProgram',
34852 => 'SpectralSensitivity',
34855 => 'ISOSpeedRatings',
34856 => 'OECF',
36864 => 'ExifVersion',
36867 => 'DateTimeOriginal',
36868 => 'DateTimeDigitized',
37121 => 'ComponentsConfiguration',
37122 => 'CompressedBitsPerPixel',
37377 => 'ShutterSpeedValue',
37378 => 'ApertureValue',
37379 => 'BrightnessValue',
37380 => 'ExposureBiasValue',
37381 => 'MaxApertureValue',
37382 => 'SubjectDistance',
37383 => 'MeteringMode',
37384 => 'LightSource',
37385 => 'Flash',
37386 => 'FocalLength',
37396 => 'SubjectArea',
37500 => 'MakerNote',
37510 => 'UserComment',
37520 => 'SubsecTime',
37521 => 'SubsecTimeOriginal',
37522 => 'SubsecTimeDigitized',
40960 => 'FlashpixVersion',
40961 => 'ColorSpace',
40962 => 'PixelXDimension',
40963 => 'PixelYDimension',
40964 => 'RelatedSoundFile',
41483 => 'FlashEnergy',
41484 => 'SpatialFrequencyResponse',
41486 => 'FocalPlaneXResolution',
41487 => 'FocalPlaneYResolution',
41488 => 'FocalPlaneResolutionUnit',
41492 => 'SubjectLocation',
41493 => 'ExposureIndex',
41495 => 'SensingMethod',
41728 => 'FileSource',
41729 => 'SceneType',
41730 => 'CFAPattern',
41985 => 'CustomRendered',
41986 => 'ExposureMode',
41987 => 'WhiteBalance',
41988 => 'DigitalZoomRatio',
41989 => 'FocalLengthIn35mmFilm',
41990 => 'SceneCaptureType',
41991 => 'GainControl',
41992 => 'Contrast',
41993 => 'Saturation',
41994 => 'Sharpness',
41995 => 'DeviceSettingDescription',
41996 => 'SubjectDistanceRange',
42016 => 'ImageUniqueID',
);
}
return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');
}
}