123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260 |
- #------------------------------------------------------------------------------
- # File: PICT.pm
- #
- # Description: Read PICT meta information
- #
- # Revisions: 10/10/2005 - P. Harvey Created
- #
- # Notes: Extraction of PICT opcodes is still experimental
- #
- # - size difference in PixPat color table?? (imagemagick reads only 1 long per entry)
- # - other differences in the way imagemagick reads 16-bit images
- #
- # References: 1) http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-2.html
- # 2) http://developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.a.htm
- #------------------------------------------------------------------------------
- package Image::ExifTool::PICT;
- use strict;
- use vars qw($VERSION);
- use Image::ExifTool qw(:DataAccess :Utils);
- $VERSION = '1.05';
- sub ReadPictValue($$$;$);
- my ($vers, $extended); # PICT version number, and extended flag
- my ($verbose, $out, $indent); # used in verbose mode
- # ranges of reserved opcodes.
- # opcodes at the start of each range must be defined in the tag table
- my @reserved = (
- 0x0017 => 0x0019, 0x0024 => 0x0027, 0x0035 => 0x0037, 0x003d => 0x003f,
- 0x0045 => 0x0047, 0x004d => 0x004f, 0x0055 => 0x0057, 0x005d => 0x005f,
- 0x0065 => 0x0067, 0x006d => 0x006f, 0x0075 => 0x0077, 0x007d => 0x007f,
- 0x0085 => 0x0087, 0x008d => 0x008f, 0x0092 => 0x0097, 0x00a2 => 0x00af,
- 0x00b0 => 0x00cf, 0x00d0 => 0x00fe, 0x0100 => 0x01ff, 0x0300 => 0x0bfe,
- 0x0c01 => 0x7eff, 0x7f00 => 0x7fff, 0x8000 => 0x80ff, 0x8100 => 0x81ff,
- 0x8201 => 0xffff,
- );
- # Apple data structures in PICT images
- my %structs = (
- Arc => [
- rect => 'Rect',
- startAng => 'int16s',
- arcAng => 'int16s',
- ],
- BitMap => [
- # (no baseAddr)
- rowBytes => 'int16u',
- bounds => 'Rect',
- ],
- # BitsRect data for PICT version 1
- BitsRect1 => [
- bitMap => 'BitMap',
- srcRect => 'Rect',
- dstRect => 'Rect',
- mode => 'int16u',
- dataSize => 'int16u',
- bitData => 'binary[$val{dataSize}]',
- ],
- # BitsRect data for PICT version 2
- BitsRect2 => [
- pixMap => 'PixMap',
- colorTable => 'ColorTable',
- srcRect => 'Rect',
- dstRect => 'Rect',
- mode => 'int16u',
- pixData => \ 'GetPixData($val{pixMap}, $raf)',
- ],
- # BitsRgn data for PICT version 1
- BitsRgn1 => [
- bitMap => 'BitMap',
- srcRect => 'Rect',
- dstRect => 'Rect',
- mode => 'int16u',
- maskRgn => 'Rgn',
- dataSize => 'int16u',
- bitData => 'binary[$val{dataSize}]',
- ],
- # BitsRgn data for PICT version 2
- BitsRgn2 => [
- pixMap => 'PixMap',
- colorTable => 'ColorTable',
- srcRect => 'Rect',
- dstRect => 'Rect',
- mode => 'int16u',
- maskRgn => 'Rgn',
- pixData => \ 'GetPixData($val{pixMap}, $raf)',
- ],
- ColorSpec => [
- value => 'int16u',
- rgb => 'RGBColor',
- ],
- ColorTable => [
- ctSeed => 'int32u',
- ctFlags => 'int16u',
- ctSize => 'int16u',
- ctTable => 'ColorSpec[$val{ctSize}+1]',
- ],
- # http://developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.a.htm
- CompressedQuickTime => [
- size => 'int32u', # size NOT including size word
- version => 'int16u',
- matrix => 'int32u[9]',
- matteSize => 'int32u',
- matteRect => 'Rect',
- mode => 'int16u',
- srcRect => 'Rect',
- accuracy => 'int32u',
- maskSize => 'int32u',
- matteDescr => 'Int32uData[$val{matteSize} ? 1 : 0]',
- matteData => 'int8u[$val{matteSize}]',
- maskRgn => 'int8u[$val{maskSize}]',
- imageDescr => 'ImageDescription',
- # size should be $val{imageDescr}->{dataSize}, but this is unreliable
- imageData => q{binary[$val{size} - 68 - $val{maskSize} - $val{imageDescr}->{size} -
- ($val{matteSize} ? $val{mattSize} + $val{matteDescr}->{size} : 0)]
- },
- ],
- DirectBitsRect => [
- baseAddr => 'int32u',
- pixMap => 'PixMap',
- srcRect => 'Rect',
- dstRect => 'Rect',
- mode => 'int16u',
- pixData => \ 'GetPixData($val{pixMap}, $raf)',
- ],
- DirectBitsRgn => [
- baseAddr => 'int32u',
- pixMap => 'PixMap',
- srcRect => 'Rect',
- dstRect => 'Rect',
- mode => 'int16u',
- maskRgn => 'Rgn',
- pixData => \ 'GetPixData($val{pixMap}, $raf)',
- ],
- # http://developer.apple.com/technotes/qd/qd_01.html
- FontName => [
- size => 'int16u', # size NOT including size word
- oldFontID => 'int16u',
- nameLen => 'int8u',
- fontName => 'string[$val{nameLen}]',
- padding => 'binary[$val{size} - $val{nameLen} - 3]',
- ],
- # http://developer.apple.com/documentation/QuickTime/APIREF/imagedescription.htm
- ImageDescription => [
- size => 'int32u', # size INCLUDING size word
- cType => 'string[4]',
- res1 => 'int32u',
- res2 => 'int16u',
- dataRefIndex => 'int16u',
- version => 'int16u',
- revision => 'int16u',
- vendor => 'string[4]',
- temporalQuality => 'int32u',
- quality => 'int32u',
- width => 'int16u',
- height => 'int16u',
- hRes => 'fixed32u',
- vRes => 'fixed32u',
- dataSize => 'int32u',
- frameCount => 'int16u',
- nameLen => 'int8u',
- compressor => 'string[31]',
- depth => 'int16u',
- clutID => 'int16u',
- clutData => 'binary[$val{size}-86]',
- ],
- Int8uText => [
- val => 'int8u',
- count => 'int8u',
- text => 'string[$val{count}]',
- ],
- Int8u2Text => [
- val => 'int8u[2]',
- count => 'int8u',
- text => 'string[$val{count}]',
- ],
- Int16Data => [
- size => 'int16u', # size NOT including size word
- data => 'int8u[$val{size}]',
- ],
- Int32uData => [
- size => 'int32u', # size NOT including size word
- data => 'int8u[$val{size}]',
- ],
- LongComment => [
- kind => 'int16u',
- size => 'int16u', # size of data only
- data => 'binary[$val{size}]',
- ],
- PixMap => [
- # Note: does not contain baseAddr
- # (except for DirectBits opcodes in which it is loaded separately)
- rowBytes => 'int16u',
- bounds => 'Rect',
- pmVersion => 'int16u',
- packType => 'int16u',
- packSize => 'int32u',
- hRes => 'fixed32s',
- vRes => 'fixed32s',
- pixelType => 'int16u',
- pixelSize => 'int16u',
- cmpCount => 'int16u',
- cmpSize => 'int16u',
- planeBytes => 'int32u',
- pmTable => 'int32u',
- pmReserved => 'int32u',
- ],
- PixPat => [
- patType => 'int16u', # 1 = non-dithered, 2 = dithered
- pat1Data => 'int8u[8]',
- # dithered PixPat has RGB entry
- RGB => 'RGBColor[$val{patType} == 2 ? 1 : 0]',
- # non-dithered PixPat has other stuff instead
- nonDithered=> 'PixPatNonDithered[$val{patType} == 2 ? 0 : 1]',
- ],
- PixPatNonDithered => [
- pixMap => 'PixMap',
- colorTable => 'ColorTable',
- pixData => \ 'GetPixData($val{pixMap}, $raf)',
- ],
- Point => [
- v => 'int16s',
- h => 'int16s',
- ],
- PointText => [
- txLoc => 'Point',
- count => 'int8u',
- text => 'string[$val{count}]',
- ],
- Polygon => [
- polySize => 'int16u',
- polyBBox => 'Rect',
- polyPoints => 'int16u[($val{polySize}-10)/2]',
- ],
- Rect => [
- topLeft => 'Point',
- botRight => 'Point',
- ],
- RGBColor => [
- red => 'int16u',
- green => 'int16u',
- blue => 'int16u',
- ],
- Rgn => [
- rgnSize => 'int16u',
- rgnBBox => 'Rect',
- data => 'int8u[$val{rgnSize}-10]',
- ],
- ShortLine => [
- pnLoc => 'Point',
- dh => 'int8s',
- dv => 'int8s',
- ],
- # http://developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.a.htm
- UncompressedQuickTime => [
- size => 'int32u', # size NOT including size word
- version => 'int16u',
- matrix => 'int32u[9]',
- matteSize => 'int32u',
- matteRect => 'Rect',
- matteDescr => 'Int32uData[$val{matteSize} ? 1 : 0]',
- matteData => 'binary[$val{matteSize}]',
- subOpcodeData => q{
- binary[ $val{size} - 50 -
- ($val{matteSize} ? $val{mattSize} + $val{matteDescr}->{size} : 0)]
- },
- ],
- );
- # PICT image opcodes
- %Image::ExifTool::PICT::Main = (
- VARS => { NO_LOOKUP => 1 }, # omit tags from lookup
- NOTES => q{
- The PICT format contains no true meta information, except for the possible
- exception of the LongComment opcode. By default, only ImageWidth,
- ImageHeight and X/YResolution are extracted from a PICT image. Tags in the
- following table represent image opcodes. Extraction of these tags is
- experimental, and is only enabled with the Verbose or Unknown options.
- },
- 0x0000 => {
- Name => 'Nop',
- Description => 'No Operation',
- Format => 'null',
- },
- 0x0001 => {
- Name => 'ClipRgn',
- Description => 'Clipping Region',
- Format => 'Rgn',
- },
- 0x0002 => {
- Name => 'BkPat',
- Description => 'Background Pattern',
- Format => 'int8u[8]',
- },
- 0x0003 => {
- Name => 'TxFont',
- Description => 'Font Number',
- Format => 'int16u',
- },
- 0x0004 => {
- Name => 'TxFace',
- Description => 'Text Font Style',
- Format => 'int8u',
- },
- 0x0005 => {
- Name => 'TxMode',
- Description => 'Text Source Mode',
- Format => 'int16u',
- },
- 0x0006 => {
- Name => 'SpExtra',
- Description => 'Extra Space',
- Format => 'fixed32s',
- },
- 0x0007 => {
- Name => 'PnSize',
- Description => 'Pen Size',
- Format => 'Point',
- },
- 0x0008 => {
- Name => 'PnMode',
- Description => 'Pen Mode',
- Format => 'int16u',
- },
- 0x0009 => {
- Name => 'PnPat',
- Description => 'Pen Pattern',
- Format => 'int8u[8]',
- },
- 0x000a => {
- Name => 'FillPat',
- Description => 'Fill Pattern',
- Format => 'int8u[8]',
- },
- 0x000b => {
- Name => 'OvSize',
- Description => 'Oval Size',
- Format => 'Point',
- },
- 0x000c => {
- Name => 'Origin',
- Format => 'Point',
- },
- 0x000d => {
- Name => 'TxSize',
- Description => 'Text Size',
- Format => 'int16u',
- },
- 0x000e => {
- Name => 'FgColor',
- Description => 'Foreground Color',
- Format => 'int32u',
- },
- 0x000f => {
- Name => 'BkColor',
- Description => 'Background Color',
- Format => 'int32u',
- },
- 0x0010 => {
- Name => 'TxRatio',
- Description => 'Text Ratio',
- Format => 'Rect',
- },
- 0x0011 => {
- Name => 'VersionOp',
- Description => 'Version',
- Format => 'int8u',
- },
- 0x0012 => {
- Name => 'BkPixPat',
- Description => 'Background Pixel Pattern',
- Format => 'PixPat',
- },
- 0x0013 => {
- Name => 'PnPixPat',
- Description => 'Pen Pixel Pattern',
- Format => 'PixPat',
- },
- 0x0014 => {
- Name => 'FillPixPat',
- Description => 'Fill Pixel Pattern',
- Format => 'PixPat',
- },
- 0x0015 => {
- Name => 'PnLocHFrac',
- Description => 'Fractional Pen Position',
- Format => 'int16u',
- },
- 0x0016 => {
- Name => 'ChExtra',
- Description => 'Added Width for NonSpace Characters',
- Format => 'int16u',
- },
- 0x0017 => {
- Name => 'Reserved',
- Format => 'Unknown',
- },
- 0x001a => {
- Name => 'RGBFgCol',
- Description => 'Foreground Color',
- Format => 'RGBColor',
- },
- 0x001b => {
- Name => 'RGBBkCol',
- Description => 'Background Color',
- Format => 'RGBColor',
- },
- 0x001c => {
- Name => 'HiliteMode',
- Description => 'Highlight Mode Flag',
- Format => 'null',
- },
- 0x001d => {
- Name => 'HiliteColor',
- Description => 'Highlight Color',
- Format => 'RGBColor',
- },
- 0x001e => {
- Name => 'DefHilite',
- Description => 'Use Default Highlight Color',
- Format => 'null',
- },
- 0x001f => {
- Name => 'OpColor',
- Format => 'RGBColor',
- },
- 0x0020 => {
- Name => 'Line',
- Format => 'Rect',
- },
- 0x0021 => {
- Name => 'LineFrom',
- Format => 'Point',
- },
- 0x0022 => {
- Name => 'ShortLine',
- Format => 'ShortLine',
- },
- 0x0023 => {
- Name => 'ShortLineFrom',
- Format => 'int8u[2]',
- },
- 0x0024 => {
- Name => 'Reserved',
- Format => 'Int16Data',
- },
- 0x0028 => {
- Name => 'LongText',
- Format => 'PointText',
- },
- 0x0029 => {
- Name => 'DHText',
- Format => 'Int8uText',
- },
- 0x002a => {
- Name => 'DVText',
- Format => 'Int8uText',
- },
- 0x002b => {
- Name => 'DHDVText',
- Format => 'Int8u2Text',
- },
- 0x002c => {
- Name => 'FontName',
- Format => 'FontName',
- },
- 0x002d => {
- Name => 'LineJustify',
- Format => 'int8u[10]',
- },
- 0x002e => {
- Name => 'GlyphState',
- Format => 'int8u[8]',
- },
- 0x002f => {
- Name => 'Reserved',
- Format => 'Int16Data',
- },
- 0x0030 => {
- Name => 'FrameRect',
- Format => 'Rect',
- },
- 0x0031 => {
- Name => 'PaintRect',
- Format => 'Rect',
- },
- 0x0032 => {
- Name => 'EraseRect',
- Format => 'Rect',
- },
- 0x0033 => {
- Name => 'InvertRect',
- Format => 'Rect',
- },
- 0x0034 => {
- Name => 'FillRect',
- Format => 'Rect',
- },
- 0x0035 => {
- Name => 'Reserved',
- Format => 'Rect',
- },
- 0x0038 => {
- Name => 'FrameSameRect',
- Format => 'null',
- },
- 0x0039 => {
- Name => 'PaintSameRect',
- Format => 'null',
- },
- 0x003a => {
- Name => 'EraseSameRect',
- Format => 'null',
- },
- 0x003b => {
- Name => 'InvertSameRect',
- Format => 'null',
- },
- 0x003c => {
- Name => 'FillSameRect',
- Format => 'null',
- },
- 0x003d => {
- Name => 'Reserved',
- Format => 'null',
- },
- 0x0040 => {
- Name => 'FrameRRect',
- Format => 'Rect',
- },
- 0x0041 => {
- Name => 'PaintRRect',
- Format => 'Rect',
- },
- 0x0042 => {
- Name => 'EraseRRect',
- Format => 'Rect',
- },
- 0x0043 => {
- Name => 'InvertRRect',
- Format => 'Rect',
- },
- 0x0044 => {
- Name => 'FillRRect',
- Format => 'Rect',
- },
- 0x0045 => {
- Name => 'Reserved',
- Format => 'Rect',
- },
- 0x0048 => {
- Name => 'FrameSameRRect',
- Format => 'null',
- },
- 0x0049 => {
- Name => 'PaintSameRRect',
- Format => 'null',
- },
- 0x004a => {
- Name => 'EraseSameRRect',
- Format => 'null',
- },
- 0x004b => {
- Name => 'InvertSameRRect',
- Format => 'null',
- },
- 0x004c => {
- Name => 'FillSameRRect',
- Format => 'null',
- },
- 0x004d => {
- Name => 'Reserved',
- Format => 'null',
- },
- 0x0050 => {
- Name => 'FrameOval',
- Format => 'Rect',
- },
- 0x0051 => {
- Name => 'PaintOval',
- Format => 'Rect',
- },
- 0x0052 => {
- Name => 'EraseOval',
- Format => 'Rect',
- },
- 0x0053 => {
- Name => 'InvertOval',
- Format => 'Rect',
- },
- 0x0054 => {
- Name => 'FillOval',
- Format => 'Rect',
- },
- 0x0055 => {
- Name => 'Reserved',
- Format => 'Rect',
- },
- 0x0058 => {
- Name => 'FrameSameOval',
- Format => 'null',
- },
- 0x0059 => {
- Name => 'PaintSameOval',
- Format => 'null',
- },
- 0x005a => {
- Name => 'EraseSameOval',
- Format => 'null',
- },
- 0x005b => {
- Name => 'InvertSameOval',
- Format => 'null',
- },
- 0x005c => {
- Name => 'FillSameOval',
- Format => 'null',
- },
- 0x005d => {
- Name => 'Reserved',
- Format => 'null',
- },
- 0x0060 => {
- Name => 'FrameArc',
- Format => 'Arc',
- },
- 0x0061 => {
- Name => 'PaintArc',
- Format => 'Arc',
- },
- 0x0062 => {
- Name => 'EraseArc',
- Format => 'Arc',
- },
- 0x0063 => {
- Name => 'InvertArc',
- Format => 'Arc',
- },
- 0x0064 => {
- Name => 'FillArc',
- Format => 'Arc',
- },
- 0x0065 => {
- Name => 'Reserved',
- Format => 'Arc',
- },
- 0x0068 => {
- Name => 'FrameSameArc',
- Format => 'Point',
- },
- 0x0069 => {
- Name => 'PaintSameArc',
- Format => 'Point',
- },
- 0x006a => {
- Name => 'EraseSameArc',
- Format => 'Point',
- },
- 0x006b => {
- Name => 'InvertSameArc',
- Format => 'Point',
- },
- 0x006c => {
- Name => 'FillSameArc',
- Format => 'Point',
- },
- 0x006d => {
- Name => 'Reserved',
- Format => 'int32u',
- },
- 0x0070 => {
- Name => 'FramePoly',
- Format => 'Polygon',
- },
- 0x0071 => {
- Name => 'PaintPoly',
- Format => 'Polygon',
- },
- 0x0072 => {
- Name => 'ErasePoly',
- Format => 'Polygon',
- },
- 0x0073 => {
- Name => 'InvertPoly',
- Format => 'Polygon',
- },
- 0x0074 => {
- Name => 'FillPoly',
- Format => 'Polygon',
- },
- 0x0075 => {
- Name => 'Reserved',
- Format => 'Polygon',
- },
- 0x0078 => {
- Name => 'FrameSamePoly',
- Format => 'null',
- },
- 0x0079 => {
- Name => 'PaintSamePoly',
- Format => 'null',
- },
- 0x007a => {
- Name => 'EraseSamePoly',
- Format => 'null',
- },
- 0x007b => {
- Name => 'InvertSamePoly',
- Format => 'null',
- },
- 0x007c => {
- Name => 'FillSamePoly',
- Format => 'null',
- },
- 0x007d => {
- Name => 'Reserved',
- Format => 'null',
- },
- 0x0080 => {
- Name => 'FrameRgn',
- Format => 'Rgn',
- },
- 0x0081 => {
- Name => 'PaintRgn',
- Format => 'Rgn',
- },
- 0x0082 => {
- Name => 'EraseRgn',
- Format => 'Rgn',
- },
- 0x0083 => {
- Name => 'InvertRgn',
- Format => 'Rgn',
- },
- 0x0084 => {
- Name => 'FillRgn',
- Format => 'Rgn',
- },
- 0x0085 => {
- Name => 'Reserved',
- Format => 'Rgn',
- },
- 0x0088 => {
- Name => 'FrameSameRgn',
- Format => 'null',
- },
- 0x0089 => {
- Name => 'PaintSameRgn',
- Format => 'null',
- },
- 0x008a => {
- Name => 'EraseSameRgn',
- Format => 'null',
- },
- 0x008b => {
- Name => 'InvertSameRgn',
- Format => 'null',
- },
- 0x008c => {
- Name => 'FillSameRgn',
- Format => 'null',
- },
- 0x008d => {
- Name => 'Reserved',
- Format => 'null',
- },
- 0x0090 => {
- Name => 'BitsRect',
- Description => 'CopyBits with Clipped Rectangle',
- Format => 'BitsRect#', # (version-dependent format)
- },
- 0x0091 => {
- Name => 'BitsRgn',
- Description => 'CopyBits with Clipped Region',
- Format => 'BitsRgn#', # (version-dependent format)
- },
- 0x0092 => {
- Name => 'Reserved',
- Format => 'Int16Data',
- },
- 0x0098 => {
- Name => 'PackBitsRect',
- Description => 'Packed CopyBits with Clipped Rectangle',
- Format => 'BitsRect#', # (version-dependent format)
- },
- 0x0099 => {
- Name => 'PackBitsRgn',
- Description => 'Packed CopyBits with Clipped Region',
- Format => 'BitsRgn#', # (version-dependent format)
- },
- 0x009a => {
- Name => 'DirectBitsRect',
- Format => 'DirectBitsRect',
- },
- 0x009b => {
- Name => 'DirectBitsRgn',
- Format => 'DirectBitsRgn',
- },
- 0x009c => {
- Name => 'Reserved',
- Format => 'Int16Data',
- },
- 0x009d => {
- Name => 'Reserved',
- Format => 'Int16Data',
- },
- 0x009e => {
- Name => 'Reserved',
- Format => 'Int16Data',
- },
- 0x009f => {
- Name => 'Reserved',
- Format => 'Int16Data',
- },
- 0x00a0 => {
- Name => 'ShortComment',
- Format => 'int16u',
- },
- 0x00a1 => [
- # this list for documentation only [currently not extracted]
- {
- # (not actually a full Photohop IRB record it appears, but it does start
- # with '8BIM', and does contain resolution information at offset 0x0a)
- Name => 'LongComment', # kind = 498
- Format => 'LongComment',
- SubDirectory => { TagTable => 'Image::ExifTool::Photoshop::Main' },
- },
- {
- Name => 'LongComment', # kind = 224
- Format => 'LongComment',
- SubDirectory => {
- TagTable => 'Image::ExifTool::ICC_Profile::Main',
- Start => '$valuePtr + 4',
- },
- },
- ],
- 0x00a2 => {
- Name => 'Reserved',
- Format => 'Int16Data',
- },
- 0x00b0 => {
- Name => 'Reserved',
- Format => 'null',
- },
- 0x00d0 => {
- Name => 'Reserved',
- Format => 'Int32uData',
- },
- 0x00ff => {
- Name => 'OpEndPic',
- Description => 'End of picture',
- Format => 'null', # 2 for version 2!?
- },
- 0x0100 => {
- Name => 'Reserved',
- Format => 'int16u',
- },
- 0x0200 => {
- Name => 'Reserved',
- Format => 'int32u',
- },
- 0x02ff => {
- Name => 'Version',
- Description => 'Version number of picture',
- Format => 'int16u',
- },
- 0x0300 => {
- Name => 'Reserved',
- Format => 'int16u',
- },
- 0x0bff => {
- Name => 'Reserved',
- Format => 'int8u[22]',
- },
- 0x0c00 => {
- Name => 'HeaderOp',
- Format => 'int16u[12]',
- },
- 0x0c01 => {
- Name => 'Reserved',
- Format => 'int8u[24]',
- },
- 0x7f00 => {
- Name => 'Reserved',
- Format => 'int8u[254]',
- },
- 0x8000 => {
- Name => 'Reserved',
- Format => 'null',
- },
- 0x8100 => {
- Name => 'Reserved',
- Format => 'Int32uData',
- },
- 0x8200 => {
- Name => 'CompressedQuickTime',
- Format => 'CompressedQuickTime',
- },
- 0x8201 => {
- Name => 'UncompressedQuickTime',
- Format => 'Int32uData',
- },
- 0xffff => {
- Name => 'Reserved',
- Format => 'Int32uData',
- },
- );
- # picture comment 'kind' codes
- # http://developer.apple.com/technotes/qd/qd_10.html
- my %commentKind = (
- 150 => 'TextBegin',
- 151 => 'TextEnd',
- 152 => 'StringBegin',
- 153 => 'StringEnd',
- 154 => 'TextCenter',
- 155 => 'LineLayoutOff',
- 156 => 'LineLayoutOn',
- 157 => 'ClientLineLayout',
- 160 => 'PolyBegin',
- 161 => 'PolyEnd',
- 163 => 'PolyIgnore',
- 164 => 'PolySmooth',
- 165 => 'PolyClose',
- 180 => 'DashedLine',
- 181 => 'DashedStop',
- 182 => 'SetLineWidth',
- 190 => 'PostScriptBegin',
- 191 => 'PostScriptEnd',
- 192 => 'PostScriptHandle',
- 193 => 'PostScriptFile',
- 194 => 'TextIsPostScript',
- 195 => 'ResourcePS',
- 196 => 'PSBeginNoSave',
- 197 => 'SetGrayLevel',
- 200 => 'RotateBegin',
- 201 => 'RotateEnd',
- 202 => 'RotateCenter',
- 210 => 'FormsPrinting',
- 211 => 'EndFormsPrinting',
- 224 => '<ICC Profile>',
- 498 => '<Photoshop Data>',
- 1000 => 'BitMapThinningOff',
- 1001 => 'BitMapThinningOn',
- );
- #------------------------------------------------------------------------------
- # Get PixData data
- # Inputs: 0) reference to PixMap, 1) RAF reference
- # Returns: reference to PixData or undef on error
- sub GetPixData($$)
- {
- my ($pixMap, $raf) = @_;
- my $packType = $pixMap->{packType};
- my $rowBytes = $pixMap->{rowBytes} & 0x3fff; # remove flags bits
- my $height = $pixMap->{bounds}->{botRight}->{v} -
- $pixMap->{bounds}->{topLeft}->{v};
- my ($data, $size, $buff, $i);
- if ($packType == 1 or $rowBytes < 8) { # unpacked data
- $size = $rowBytes * $height;
- return undef unless $raf->Read($data, $size) == $size;
- } elsif ($packType == 2) { # pad byte dropped
- $size = int($rowBytes * $height * 3 / 4 + 0.5);
- return undef unless $raf->Read($data, $size) == $size;
- } else {
- $data = '';
- for ($i=0; $i<$height; ++$i) {
- if ($rowBytes > 250) {
- $raf->Read($buff,2) == 2 or return undef;
- $size = unpack('n',$buff);
- } else {
- $raf->Read($buff,1) == 1 or return undef;
- $size = unpack('C',$buff);
- }
- $data .= $buff;
- $raf->Read($buff,$size) == $size or return undef;
- $data .= $buff;
- }
- }
- return \$data;
- }
- #------------------------------------------------------------------------------
- # Read value from PICT file
- # Inputs: 0) RAF reference, 1) tag, 2) format, 3) optional count
- # Returns: value, reference to structure hash, or undef on error
- sub ReadPictValue($$$;$)
- {
- my ($raf, $tag, $format, $count) = @_;
- return undef unless $format;
- unless (defined $count) {
- if ($format =~ /(.+)\[(.+)\]/s) {
- $format = $1;
- $count = $2;
- } else {
- $count = 1; # count undefined: assume 1
- }
- }
- my $cntStr = ($count == 1) ? '' : "[$count]";
- # no size if count is 0
- my $size = $count ? Image::ExifTool::FormatSize($format) : 0;
- if (defined $size or $format eq 'null') {
- my $val;
- if ($size) {
- my $buff;
- $size *= $count;
- $raf->Read($buff, $size) == $size or return undef;
- $val = ReadValue(\$buff, 0, $format, $count, $size);
- } else {
- $val = '';
- }
- if ($verbose) {
- print $out "${indent}$tag ($format$cntStr)";
- if ($size) {
- if (not defined $val) {
- print $out " = <undef>\n";
- } elsif ($format eq 'binary') {
- print $out " = <binary data>\n";
- if ($verbose > 2) {
- my %parms = ( Out => $out );
- $parms{MaxLen} = 96 if $verbose < 4;
- HexDump(\$val, undef, %parms);
- }
- } else {
- print $out " = $val\n";
- }
- } else {
- print $out "\n";
- }
- }
- return \$val if $format eq 'binary' and defined $val;
- return $val;
- }
- $verbose and print $out "${indent}$tag ($format$cntStr):\n";
- my $struct = $structs{$format} or return undef;
- my ($c, @vals);
- for ($c=0; $c<$count; ++$c) {
- my (%val, $i);
- for ($i=0; ; $i+=2) {
- my $tag = $$struct[$i] or last;
- my $fmt = $$struct[$i+1];
- my ($cnt, $val);
- $indent .= ' ';
- if (ref $fmt) {
- $val = eval $$fmt;
- $@ and warn $@;
- if ($verbose and defined $val) {
- printf $out "${indent}$tag (binary[%d]) = <binary data>\n",length($$val);
- if ($verbose > 2) {
- my %parms = ( Out => $out );
- $parms{MaxLen} = 96 if $verbose < 4;
- HexDump($val, undef, %parms);
- }
- }
- } elsif ($fmt =~ /(.+)\[(.+)\]/s) {
- $fmt = $1;
- $cnt = eval $2;
- $@ and warn $@;
- $val = ReadPictValue($raf, $tag, $fmt, $cnt);
- } else {
- $val = ReadPictValue($raf, $tag, $fmt);
- }
- $indent = substr($indent, 2);
- return undef unless defined $val;
- $val{$tag} = $val;
- }
- return \%val if $count == 1;
- push @vals, \%val;
- }
- return \@vals;
- }
- #------------------------------------------------------------------------------
- # Extract meta information from a PICT image
- # Inputs: 0) ExifTool object reference, 1) dirInfo reference
- # Returns: 1 on success, 0 if this wasn't a valid PICT image
- sub ProcessPICT($$)
- {
- my ($et, $dirInfo) = @_;
- my $raf = $$dirInfo{RAF};
- $verbose = $et->Options('Verbose');
- $out = $et->Options('TextOut');
- $indent = '';
- my ($buff, $tried, @hdr, $op, $hRes, $vRes);
- # recognize both PICT files and PICT resources (PICT files have a
- # 512-byte header that we ignore, but PICT resources do not)
- for (;;) {
- $raf->Read($buff, 12) == 12 or return 0;
- @hdr = unpack('x2n5', $buff);
- $op = pop @hdr;
- # check for PICT version 1 format
- if ($op eq 0x1101) {
- $vers = 1;
- undef $extended;
- last;
- }
- # check for PICT version 2 format
- if ($op eq 0x0011) {
- $raf->Read($buff, 28) == 28 or return 0;
- if ($buff =~ /^\x02\xff\x0c\x00\xff\xff/) {
- $vers = 2;
- undef $extended;
- last;
- }
- if ($buff =~ /^\x02\xff\x0c\x00\xff\xfe/) {
- $vers = 2;
- $extended = 1;
- ($hRes, $vRes) = unpack('x8N2', $buff);
- last;
- }
- }
- return 0 if $tried;
- $tried = 1;
- $raf->Seek(512, 0) or return 0;
- }
- # make the bounding rect signed
- foreach (@hdr) {
- $_ >= 0x8000 and $_ -= 0x10000;
- }
- my $w = $hdr[3] - $hdr[1];
- my $h = $hdr[2] - $hdr[0];
- return 0 unless $w > 0 and $h > 0;
- SetByteOrder('MM');
- if ($extended) {
- # extended version 2 pictures contain resolution information
- # and image bounds are in 72-dpi equivalent units
- $hRes = GetFixed32s(\$buff, 8);
- $vRes = GetFixed32s(\$buff, 12);
- return 0 unless $hRes and $vRes;
- $w = int($w * $hRes / 72 + 0.5);
- $h = int($h * $vRes / 72 + 0.5);
- }
- $et->SetFileType();
- $et->FoundTag('ImageWidth', $w);
- $et->FoundTag('ImageHeight', $h);
- $et->FoundTag('XResolution', $hRes) if $hRes;
- $et->FoundTag('YResolution', $vRes) if $vRes;
- # don't extract image opcodes unless verbose
- return 1 unless $verbose or $et->Options('Unknown');
- $verbose and printf $out "PICT version $vers%s\n", $extended ? ' extended' : '';
- my $tagTablePtr = GetTagTable('Image::ExifTool::PICT::Main');
- my $success;
- for (;;) {
- if ($vers == 1) {
- $raf->Read($buff, 1) == 1 or last;
- $op = ord($buff);
- } else {
- # must start version 2 opcode on an even byte
- $raf->Read($buff, 1) if $raf->Tell() & 0x01;
- $raf->Read($buff, 2) == 2 or last;
- $op = unpack('n', $buff);
- }
- my $tagInfo = $et->GetTagInfo($tagTablePtr, $op);
- unless ($tagInfo) {
- my $i;
- # search for reserved tag info
- for ($i=0; $i<scalar(@reserved); $i+=2) {
- next unless $op >= $reserved[$i];
- last if $op > $reserved[$i+1];
- $tagInfo = $et->GetTagInfo($tagTablePtr, $reserved[$i]);
- last;
- }
- last unless $tagInfo;
- }
- if ($op eq 0xff) {
- $verbose and print $out "End of picture\n";
- $success = 1;
- last;
- }
- my $format = $$tagInfo{Format};
- unless ($format) {
- $et->Warn("Missing format for $$tagInfo{Name}");
- last;
- }
- # replace version number for version-dependent formats
- $format =~ s/#$/$vers/;
- my $wid = $vers * 2;
- $verbose and printf $out "Tag 0x%.${wid}x, ", $op;
- my $val = ReadPictValue($raf, $$tagInfo{Name}, $format);
- unless (defined $val) {
- $et->Warn("Error reading $$tagInfo{Name} information");
- last;
- }
- if (ref $val eq 'HASH') {
- # extract JPEG image from CompressedQuickTime imageData
- if ($$tagInfo{Name} eq 'CompressedQuickTime' and
- ref $val->{imageDescr} eq 'HASH' and
- $val->{imageDescr}->{compressor} and
- $val->{imageDescr}->{compressor} eq 'Photo - JPEG' and
- ref $val->{imageData} eq 'SCALAR' and
- $et->ValidateImage($val->{imageData}, 'PreviewImage'))
- {
- $et->FoundTag('PreviewImage', $val->{imageData});
- }
- } else {
- # $et->FoundTag($tagInfo, $val);
- }
- }
- $success or $et->Warn('End of picture not found');
- return 1;
- }
- 1; # end
- __END__
- =head1 NAME
- Image::ExifTool::PICT - Read PICT meta information
- =head1 SYNOPSIS
- This module is used by Image::ExifTool
- =head1 DESCRIPTION
- This module contains routines required by Image::ExifTool to read PICT
- (Apple Picture) images.
- =head1 NOTES
- Extraction of PICT opcodes is experimental, and is only enabled with the
- Verbose or the Unknown option.
- =head1 AUTHOR
- Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
- This library is free software; you can redistribute it and/or modify it
- under the same terms as Perl itself.
- =head1 REFERENCES
- =over 4
- =item L<http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-2.html>
- =item L<http://developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.a.htm>
- =back
- =head1 SEE ALSO
- L<Image::ExifTool::TagNames/PICT Tags>,
- L<Image::ExifTool(3pm)|Image::ExifTool>
- =cut
|