source: gsdl/trunk/perllib/cpan/Image/ExifTool/PICT.pm@ 16842

Last change on this file since 16842 was 16842, checked in by davidb, 16 years ago

ExifTool added to cpan area to support metadata extraction from files such as JPEG. Primarily targetted as Image files (hence the Image folder name decided upon by the ExifTool author) it also can handle video such as flash and audio such as Wav

File size: 33.3 KB
Line 
1#------------------------------------------------------------------------------
2# File: PICT.pm
3#
4# Description: Read PICT meta information
5#
6# Revisions: 10/10/2005 - P. Harvey Created
7#
8# Notes: Extraction of PICT opcodes is still experimental
9#
10# - size difference in PixPat color table?? (imagemagick reads only 1 long per entry)
11# - other differences in the way imagemagick reads 16-bit images
12#
13# References: 1) http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-2.html
14# 2) http://developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.a.htm
15#------------------------------------------------------------------------------
16
17package Image::ExifTool::PICT;
18
19use strict;
20use vars qw($VERSION);
21use Image::ExifTool qw(:DataAccess :Utils);
22
23$VERSION = '1.03';
24
25sub ReadPictValue($$$;$);
26
27my ($vers, $extended); # PICT version number, and extended flag
28my ($verbose, $out, $indent); # used in verbose mode
29
30# ranges of reserved opcodes.
31# opcodes at the start of each range must be defined in the tag table
32my @reserved = (
33 0x0017 => 0x0019, 0x0024 => 0x0027, 0x0035 => 0x0037, 0x003d => 0x003f,
34 0x0045 => 0x0047, 0x004d => 0x004f, 0x0055 => 0x0057, 0x005d => 0x005f,
35 0x0065 => 0x0067, 0x006d => 0x006f, 0x0075 => 0x0077, 0x007d => 0x007f,
36 0x0085 => 0x0087, 0x008d => 0x008f, 0x0092 => 0x0097, 0x00a2 => 0x00af,
37 0x00b0 => 0x00cf, 0x00d0 => 0x00fe, 0x0100 => 0x01ff, 0x0300 => 0x0bfe,
38 0x0c01 => 0x7eff, 0x7f00 => 0x7fff, 0x8000 => 0x80ff, 0x8100 => 0x81ff,
39 0x8201 => 0xffff,
40);
41
42# Apple data structures in PICT images
43my %structs = (
44 Arc => [
45 rect => 'Rect',
46 startAng => 'int16s',
47 arcAng => 'int16s',
48 ],
49 BitMap => [
50 # (no baseAddr)
51 rowBytes => 'int16u',
52 bounds => 'Rect',
53 ],
54 # BitsRect data for PICT version 1
55 BitsRect1 => [
56 bitMap => 'BitMap',
57 srcRect => 'Rect',
58 dstRect => 'Rect',
59 mode => 'int16u',
60 dataSize => 'int16u',
61 bitData => 'binary[$val{dataSize}]',
62 ],
63 # BitsRect data for PICT version 2
64 BitsRect2 => [
65 pixMap => 'PixMap',
66 colorTable => 'ColorTable',
67 srcRect => 'Rect',
68 dstRect => 'Rect',
69 mode => 'int16u',
70 pixData => \ 'GetPixData($val{pixMap}, $raf)',
71 ],
72 # BitsRgn data for PICT version 1
73 BitsRgn1 => [
74 bitMap => 'BitMap',
75 srcRect => 'Rect',
76 dstRect => 'Rect',
77 mode => 'int16u',
78 maskRgn => 'Rgn',
79 dataSize => 'int16u',
80 bitData => 'binary[$val{dataSize}]',
81 ],
82 # BitsRgn data for PICT version 2
83 BitsRgn2 => [
84 pixMap => 'PixMap',
85 colorTable => 'ColorTable',
86 srcRect => 'Rect',
87 dstRect => 'Rect',
88 mode => 'int16u',
89 maskRgn => 'Rgn',
90 pixData => \ 'GetPixData($val{pixMap}, $raf)',
91 ],
92 ColorSpec => [
93 value => 'int16u',
94 rgb => 'RGBColor',
95 ],
96 ColorTable => [
97 ctSeed => 'int32u',
98 ctFlags => 'int16u',
99 ctSize => 'int16u',
100 ctTable => 'ColorSpec[$val{ctSize}+1]',
101 ],
102 # http://developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.a.htm
103 CompressedQuickTime => [
104 size => 'int32u', # size NOT including size word
105 version => 'int16u',
106 matrix => 'int32u[9]',
107 matteSize => 'int32u',
108 matteRect => 'Rect',
109 mode => 'int16u',
110 srcRect => 'Rect',
111 accuracy => 'int32u',
112 maskSize => 'int32u',
113 matteDescr => 'Int32uData[$val{matteSize} ? 1 : 0]',
114 matteData => 'int8u[$val{matteSize}]',
115 maskRgn => 'int8u[$val{maskSize}]',
116 imageDescr => 'ImageDescription',
117 # size should be $val{imageDescr}->{dataSize}, but this is unreliable
118 imageData => q{binary[$val{size} - 68 - $val{maskSize} - $val{imageDescr}->{size} -
119 ($val{matteSize} ? $val{mattSize} + $val{matteDescr}->{size} : 0)]
120 },
121 ],
122 DirectBitsRect => [
123 baseAddr => 'int32u',
124 pixMap => 'PixMap',
125 srcRect => 'Rect',
126 dstRect => 'Rect',
127 mode => 'int16u',
128 pixData => \ 'GetPixData($val{pixMap}, $raf)',
129 ],
130 DirectBitsRgn => [
131 baseAddr => 'int32u',
132 pixMap => 'PixMap',
133 srcRect => 'Rect',
134 dstRect => 'Rect',
135 mode => 'int16u',
136 maskRgn => 'Rgn',
137 pixData => \ 'GetPixData($val{pixMap}, $raf)',
138 ],
139 # http://developer.apple.com/technotes/qd/qd_01.html
140 FontName => [
141 size => 'int16u', # size NOT including size word
142 oldFontID => 'int16u',
143 nameLen => 'int8u',
144 fontName => 'string[$val{nameLen}]',
145 padding => 'binary[$val{size} - $val{nameLen} - 3]',
146 ],
147 # http://developer.apple.com/documentation/QuickTime/APIREF/imagedescription.htm
148 ImageDescription => [
149 size => 'int32u', # size INCLUDING size word
150 cType => 'string[4]',
151 res1 => 'int32u',
152 res2 => 'int16u',
153 dataRefIndex => 'int16u',
154 version => 'int16u',
155 revision => 'int16u',
156 vendor => 'string[4]',
157 temporalQuality => 'int32u',
158 quality => 'int32u',
159 width => 'int16u',
160 height => 'int16u',
161 hRes => 'fixed32u',
162 vRes => 'fixed32u',
163 dataSize => 'int32u',
164 frameCount => 'int16u',
165 nameLen => 'int8u',
166 compressor => 'string[31]',
167 depth => 'int16u',
168 clutID => 'int16u',
169 clutData => 'binary[$val{size}-86]',
170 ],
171 Int8uText => [
172 val => 'int8u',
173 count => 'int8u',
174 text => 'string[$val{count}]',
175 ],
176 Int8u2Text => [
177 val => 'int8u[2]',
178 count => 'int8u',
179 text => 'string[$val{count}]',
180 ],
181 Int16Data => [
182 size => 'int16u', # size NOT including size word
183 data => 'int8u[$val{size}]',
184 ],
185 Int32uData => [
186 size => 'int32u', # size NOT including size word
187 data => 'int8u[$val{size}]',
188 ],
189 LongComment => [
190 kind => 'int16u',
191 size => 'int16u', # size of data only
192 data => 'binary[$val{size}]',
193 ],
194 PixMap => [
195 # Note: does not contain baseAddr
196 # (except for DirectBits opcodes in which it is loaded separately)
197 rowBytes => 'int16u',
198 bounds => 'Rect',
199 pmVersion => 'int16u',
200 packType => 'int16u',
201 packSize => 'int32u',
202 hRes => 'fixed32s',
203 vRes => 'fixed32s',
204 pixelType => 'int16u',
205 pixelSize => 'int16u',
206 cmpCount => 'int16u',
207 cmpSize => 'int16u',
208 planeBytes => 'int32u',
209 pmTable => 'int32u',
210 pmReserved => 'int32u',
211 ],
212 PixPat => [
213 patType => 'int16u', # 1 = non-dithered, 2 = dithered
214 pat1Data => 'int8u[8]',
215 # dithered PixPat has RGB entry
216 RGB => 'RGBColor[$val{patType} == 2 ? 1 : 0]',
217 # non-dithered PixPat has other stuff instead
218 nonDithered=> 'PixPatNonDithered[$val{patType} == 2 ? 0 : 1]',
219 ],
220 PixPatNonDithered => [
221 pixMap => 'PixMap',
222 colorTable => 'ColorTable',
223 pixData => \ 'GetPixData($val{pixMap}, $raf)',
224 ],
225 Point => [
226 v => 'int16s',
227 h => 'int16s',
228 ],
229 PointText => [
230 txLoc => 'Point',
231 count => 'int8u',
232 text => 'string[$val{count}]',
233 ],
234 Polygon => [
235 polySize => 'int16u',
236 polyBBox => 'Rect',
237 polyPoints => 'int16u[($val{polySize}-10)/2]',
238 ],
239 Rect => [
240 topLeft => 'Point',
241 botRight => 'Point',
242 ],
243 RGBColor => [
244 red => 'int16u',
245 green => 'int16u',
246 blue => 'int16u',
247 ],
248 Rgn => [
249 rgnSize => 'int16u',
250 rgnBBox => 'Rect',
251 data => 'int8u[$val{rgnSize}-10]',
252 ],
253 ShortLine => [
254 pnLoc => 'Point',
255 dh => 'int8s',
256 dv => 'int8s',
257 ],
258 # http://developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.a.htm
259 UncompressedQuickTime => [
260 size => 'int32u', # size NOT including size word
261 version => 'int16u',
262 matrix => 'int32u[9]',
263 matteSize => 'int32u',
264 matteRect => 'Rect',
265 matteDescr => 'Int32uData[$val{matteSize} ? 1 : 0]',
266 matteData => 'binary[$val{matteSize}]',
267 subOpcodeData => q{
268 binary[ $val{size} - 50 -
269 ($val{matteSize} ? $val{mattSize} + $val{matteDescr}->{size} : 0)]
270 },
271 ],
272);
273
274# PICT image opcodes
275%Image::ExifTool::PICT::Main = (
276 PROCESS_PROC => 0, # set this to zero to omit tags from lookup
277 NOTES => q{
278The PICT format contains no true meta information, except for the possible
279exception of the LongComment opcode. By default, only ImageWidth,
280ImageHeight and X/YResolution are extracted from a PICT image. Tags in the
281following table represent image opcodes. Extraction of these tags is
282experimental, and is only enabled with the Verbose or Unknown options.
283 },
284 0x0000 => {
285 Name => 'Nop',
286 Description => 'No Operation',
287 Format => 'null',
288 },
289 0x0001 => {
290 Name => 'ClipRgn',
291 Description => 'Clipping Region',
292 Format => 'Rgn',
293 },
294 0x0002 => {
295 Name => 'BkPat',
296 Description => 'Background Pattern',
297 Format => 'int8u[8]',
298 },
299 0x0003 => {
300 Name => 'TxFont',
301 Description => 'Font Number',
302 Format => 'int16u',
303 },
304 0x0004 => {
305 Name => 'TxFace',
306 Description => 'Text Font Style',
307 Format => 'int8u',
308 },
309 0x0005 => {
310 Name => 'TxMode',
311 Description => 'Text Source Mode',
312 Format => 'int16u',
313 },
314 0x0006 => {
315 Name => 'SpExtra',
316 Description => 'Extra Space',
317 Format => 'fixed32s',
318 },
319 0x0007 => {
320 Name => 'PnSize',
321 Description => 'Pen Size',
322 Format => 'Point',
323 },
324 0x0008 => {
325 Name => 'PnMode',
326 Description => 'Pen Mode',
327 Format => 'int16u',
328 },
329 0x0009 => {
330 Name => 'PnPat',
331 Description => 'Pen Pattern',
332 Format => 'int8u[8]',
333 },
334 0x000a => {
335 Name => 'FillPat',
336 Description => 'Fill Pattern',
337 Format => 'int8u[8]',
338 },
339 0x000b => {
340 Name => 'OvSize',
341 Description => 'Oval Size',
342 Format => 'Point',
343 },
344 0x000c => {
345 Name => 'Origin',
346 Format => 'Point',
347 },
348 0x000d => {
349 Name => 'TxSize',
350 Description => 'Text Size',
351 Format => 'int16u',
352 },
353 0x000e => {
354 Name => 'FgColor',
355 Description => 'Foreground Color',
356 Format => 'int32u',
357 },
358 0x000f => {
359 Name => 'BkColor',
360 Description => 'Background Color',
361 Format => 'int32u',
362 },
363 0x0010 => {
364 Name => 'TxRatio',
365 Description => 'Text Ratio',
366 Format => 'Rect',
367 },
368 0x0011 => {
369 Name => 'VersionOp',
370 Description => 'Version',
371 Format => 'int8u',
372 },
373 0x0012 => {
374 Name => 'BkPixPat',
375 Description => 'Background Pixel Pattern',
376 Format => 'PixPat',
377 },
378 0x0013 => {
379 Name => 'PnPixPat',
380 Description => 'Pen Pixel Pattern',
381 Format => 'PixPat',
382 },
383 0x0014 => {
384 Name => 'FillPixPat',
385 Description => 'Fill Pixel Pattern',
386 Format => 'PixPat',
387 },
388 0x0015 => {
389 Name => 'PnLocHFrac',
390 Description => 'Fractional Pen Position',
391 Format => 'int16u',
392 },
393 0x0016 => {
394 Name => 'ChExtra',
395 Description => 'Added Width for NonSpace Characters',
396 Format => 'int16u',
397 },
398 0x0017 => {
399 Name => 'Reserved',
400 Format => 'Unknown',
401 },
402 0x001a => {
403 Name => 'RGBFgCol',
404 Description => 'Foreground Color',
405 Format => 'RGBColor',
406 },
407 0x001b => {
408 Name => 'RGBBkCol',
409 Description => 'Background Color',
410 Format => 'RGBColor',
411 },
412 0x001c => {
413 Name => 'HiliteMode',
414 Description => 'Highlight Mode Flag',
415 Format => 'null',
416 },
417 0x001d => {
418 Name => 'HiliteColor',
419 Description => 'Highlight Color',
420 Format => 'RGBColor',
421 },
422 0x001e => {
423 Name => 'DefHilite',
424 Description => 'Use Default Highlight Color',
425 Format => 'null',
426 },
427 0x001f => {
428 Name => 'OpColor',
429 Format => 'RGBColor',
430 },
431 0x0020 => {
432 Name => 'Line',
433 Format => 'Rect',
434 },
435 0x0021 => {
436 Name => 'LineFrom',
437 Format => 'Point',
438 },
439 0x0022 => {
440 Name => 'ShortLine',
441 Format => 'ShortLine',
442 },
443 0x0023 => {
444 Name => 'ShortLineFrom',
445 Format => 'int8u[2]',
446 },
447 0x0024 => {
448 Name => 'Reserved',
449 Format => 'Int16Data',
450 },
451 0x0028 => {
452 Name => 'LongText',
453 Format => 'PointText',
454 },
455 0x0029 => {
456 Name => 'DHText',
457 Format => 'Int8uText',
458 },
459 0x002a => {
460 Name => 'DVText',
461 Format => 'Int8uText',
462 },
463 0x002b => {
464 Name => 'DHDVText',
465 Format => 'Int8u2Text',
466 },
467 0x002c => {
468 Name => 'FontName',
469 Format => 'FontName',
470 },
471 0x002d => {
472 Name => 'LineJustify',
473 Format => 'int8u[10]',
474 },
475 0x002e => {
476 Name => 'GlyphState',
477 Format => 'int8u[8]',
478 },
479 0x002f => {
480 Name => 'Reserved',
481 Format => 'Int16Data',
482 },
483 0x0030 => {
484 Name => 'FrameRect',
485 Format => 'Rect',
486 },
487 0x0031 => {
488 Name => 'PaintRect',
489 Format => 'Rect',
490 },
491 0x0032 => {
492 Name => 'EraseRect',
493 Format => 'Rect',
494 },
495 0x0033 => {
496 Name => 'InvertRect',
497 Format => 'Rect',
498 },
499 0x0034 => {
500 Name => 'FillRect',
501 Format => 'Rect',
502 },
503 0x0035 => {
504 Name => 'Reserved',
505 Format => 'Rect',
506 },
507 0x0038 => {
508 Name => 'FrameSameRect',
509 Format => 'null',
510 },
511 0x0039 => {
512 Name => 'PaintSameRect',
513 Format => 'null',
514 },
515 0x003a => {
516 Name => 'EraseSameRect',
517 Format => 'null',
518 },
519 0x003b => {
520 Name => 'InvertSameRect',
521 Format => 'null',
522 },
523 0x003c => {
524 Name => 'FillSameRect',
525 Format => 'null',
526 },
527 0x003d => {
528 Name => 'Reserved',
529 Format => 'null',
530 },
531 0x0040 => {
532 Name => 'FrameRRect',
533 Format => 'Rect',
534 },
535 0x0041 => {
536 Name => 'PaintRRect',
537 Format => 'Rect',
538 },
539 0x0042 => {
540 Name => 'EraseRRect',
541 Format => 'Rect',
542 },
543 0x0043 => {
544 Name => 'InvertRRect',
545 Format => 'Rect',
546 },
547 0x0044 => {
548 Name => 'FillRRect',
549 Format => 'Rect',
550 },
551 0x0045 => {
552 Name => 'Reserved',
553 Format => 'Rect',
554 },
555 0x0048 => {
556 Name => 'FrameSameRRect',
557 Format => 'null',
558 },
559 0x0049 => {
560 Name => 'PaintSameRRect',
561 Format => 'null',
562 },
563 0x004a => {
564 Name => 'EraseSameRRect',
565 Format => 'null',
566 },
567 0x004b => {
568 Name => 'InvertSameRRect',
569 Format => 'null',
570 },
571 0x004c => {
572 Name => 'FillSameRRect',
573 Format => 'null',
574 },
575 0x004d => {
576 Name => 'Reserved',
577 Format => 'null',
578 },
579 0x0050 => {
580 Name => 'FrameOval',
581 Format => 'Rect',
582 },
583 0x0051 => {
584 Name => 'PaintOval',
585 Format => 'Rect',
586 },
587 0x0052 => {
588 Name => 'EraseOval',
589 Format => 'Rect',
590 },
591 0x0053 => {
592 Name => 'InvertOval',
593 Format => 'Rect',
594 },
595 0x0054 => {
596 Name => 'FillOval',
597 Format => 'Rect',
598 },
599 0x0055 => {
600 Name => 'Reserved',
601 Format => 'Rect',
602 },
603 0x0058 => {
604 Name => 'FrameSameOval',
605 Format => 'null',
606 },
607 0x0059 => {
608 Name => 'PaintSameOval',
609 Format => 'null',
610 },
611 0x005a => {
612 Name => 'EraseSameOval',
613 Format => 'null',
614 },
615 0x005b => {
616 Name => 'InvertSameOval',
617 Format => 'null',
618 },
619 0x005c => {
620 Name => 'FillSameOval',
621 Format => 'null',
622 },
623 0x005d => {
624 Name => 'Reserved',
625 Format => 'null',
626 },
627 0x0060 => {
628 Name => 'FrameArc',
629 Format => 'Arc',
630 },
631 0x0061 => {
632 Name => 'PaintArc',
633 Format => 'Arc',
634 },
635 0x0062 => {
636 Name => 'EraseArc',
637 Format => 'Arc',
638 },
639 0x0063 => {
640 Name => 'InvertArc',
641 Format => 'Arc',
642 },
643 0x0064 => {
644 Name => 'FillArc',
645 Format => 'Arc',
646 },
647 0x0065 => {
648 Name => 'Reserved',
649 Format => 'Arc',
650 },
651 0x0068 => {
652 Name => 'FrameSameArc',
653 Format => 'Point',
654 },
655 0x0069 => {
656 Name => 'PaintSameArc',
657 Format => 'Point',
658 },
659 0x006a => {
660 Name => 'EraseSameArc',
661 Format => 'Point',
662 },
663 0x006b => {
664 Name => 'InvertSameArc',
665 Format => 'Point',
666 },
667 0x006c => {
668 Name => 'FillSameArc',
669 Format => 'Point',
670 },
671 0x006d => {
672 Name => 'Reserved',
673 Format => 'int32u',
674 },
675 0x0070 => {
676 Name => 'FramePoly',
677 Format => 'Polygon',
678 },
679 0x0071 => {
680 Name => 'PaintPoly',
681 Format => 'Polygon',
682 },
683 0x0072 => {
684 Name => 'ErasePoly',
685 Format => 'Polygon',
686 },
687 0x0073 => {
688 Name => 'InvertPoly',
689 Format => 'Polygon',
690 },
691 0x0074 => {
692 Name => 'FillPoly',
693 Format => 'Polygon',
694 },
695 0x0075 => {
696 Name => 'Reserved',
697 Format => 'Polygon',
698 },
699 0x0078 => {
700 Name => 'FrameSamePoly',
701 Format => 'null',
702 },
703 0x0079 => {
704 Name => 'PaintSamePoly',
705 Format => 'null',
706 },
707 0x007a => {
708 Name => 'EraseSamePoly',
709 Format => 'null',
710 },
711 0x007b => {
712 Name => 'InvertSamePoly',
713 Format => 'null',
714 },
715 0x007c => {
716 Name => 'FillSamePoly',
717 Format => 'null',
718 },
719 0x007d => {
720 Name => 'Reserved',
721 Format => 'null',
722 },
723 0x0080 => {
724 Name => 'FrameRgn',
725 Format => 'Rgn',
726 },
727 0x0081 => {
728 Name => 'PaintRgn',
729 Format => 'Rgn',
730 },
731 0x0082 => {
732 Name => 'EraseRgn',
733 Format => 'Rgn',
734 },
735 0x0083 => {
736 Name => 'InvertRgn',
737 Format => 'Rgn',
738 },
739 0x0084 => {
740 Name => 'FillRgn',
741 Format => 'Rgn',
742 },
743 0x0085 => {
744 Name => 'Reserved',
745 Format => 'Rgn',
746 },
747 0x0088 => {
748 Name => 'FrameSameRgn',
749 Format => 'null',
750 },
751 0x0089 => {
752 Name => 'PaintSameRgn',
753 Format => 'null',
754 },
755 0x008a => {
756 Name => 'EraseSameRgn',
757 Format => 'null',
758 },
759 0x008b => {
760 Name => 'InvertSameRgn',
761 Format => 'null',
762 },
763 0x008c => {
764 Name => 'FillSameRgn',
765 Format => 'null',
766 },
767 0x008d => {
768 Name => 'Reserved',
769 Format => 'null',
770 },
771 0x0090 => {
772 Name => 'BitsRect',
773 Description => 'CopyBits with Clipped Rectangle',
774 Format => 'BitsRect#', # (version-dependent format)
775 },
776 0x0091 => {
777 Name => 'BitsRgn',
778 Description => 'CopyBits with Clipped Region',
779 Format => 'BitsRgn#', # (version-dependent format)
780 },
781 0x0092 => {
782 Name => 'Reserved',
783 Format => 'Int16Data',
784 },
785 0x0098 => {
786 Name => 'PackBitsRect',
787 Description => 'Packed CopyBits with Clipped Rectangle',
788 Format => 'BitsRect#', # (version-dependent format)
789 },
790 0x0099 => {
791 Name => 'PackBitsRgn',
792 Description => 'Packed CopyBits with Clipped Region',
793 Format => 'BitsRgn#', # (version-dependent format)
794 },
795 0x009a => {
796 Name => 'DirectBitsRect',
797 Format => 'DirectBitsRect',
798 },
799 0x009b => {
800 Name => 'DirectBitsRgn',
801 Format => 'DirectBitsRgn',
802 },
803 0x009c => {
804 Name => 'Reserved',
805 Format => 'Int16Data',
806 },
807 0x009d => {
808 Name => 'Reserved',
809 Format => 'Int16Data',
810 },
811 0x009e => {
812 Name => 'Reserved',
813 Format => 'Int16Data',
814 },
815 0x009f => {
816 Name => 'Reserved',
817 Format => 'Int16Data',
818 },
819 0x00a0 => {
820 Name => 'ShortComment',
821 Format => 'int16u',
822 },
823 0x00a1 => [
824 # this list for documentation only [not currently extracted]
825 {
826 # (not actually a full Photohop IRB record it appears, but it does start
827 # with '8BIM', and does contain resolution information at offset 0x0a)
828 Name => 'LongComment', # kind = 498
829 Format => 'LongComment',
830 SubDirectory => { TagTable => 'Image::ExifTool::Photoshop::Main' },
831 },
832 {
833 Name => 'LongComment', # kind = 224
834 Format => 'LongComment',
835 SubDirectory => {
836 TagTable => 'Image::ExifTool::ICC_Profile::Main',
837 Start => '$valuePtr + 4',
838 },
839 },
840 ],
841 0x00a2 => {
842 Name => 'Reserved',
843 Format => 'Int16Data',
844 },
845 0x00b0 => {
846 Name => 'Reserved',
847 Format => 'null',
848 },
849 0x00d0 => {
850 Name => 'Reserved',
851 Format => 'Int32uData',
852 },
853 0x00ff => {
854 Name => 'OpEndPic',
855 Description => 'End of picture',
856 Format => 'null', # 2 for version 2!?
857 },
858 0x0100 => {
859 Name => 'Reserved',
860 Format => 'int16u',
861 },
862 0x0200 => {
863 Name => 'Reserved',
864 Format => 'int32u',
865 },
866 0x02ff => {
867 Name => 'Version',
868 Description => 'Version number of picture',
869 Format => 'int16u',
870 },
871 0x0300 => {
872 Name => 'Reserved',
873 Format => 'int16u',
874 },
875 0x0bff => {
876 Name => 'Reserved',
877 Format => 'int8u[22]',
878 },
879 0x0c00 => {
880 Name => 'HeaderOp',
881 Format => 'int16u[12]',
882 },
883 0x0c01 => {
884 Name => 'Reserved',
885 Format => 'int8u[24]',
886 },
887 0x7f00 => {
888 Name => 'Reserved',
889 Format => 'int8u[254]',
890 },
891 0x8000 => {
892 Name => 'Reserved',
893 Format => 'null',
894 },
895 0x8100 => {
896 Name => 'Reserved',
897 Format => 'Int32uData',
898 },
899 0x8200 => {
900 Name => 'CompressedQuickTime',
901 Format => 'CompressedQuickTime',
902 },
903 0x8201 => {
904 Name => 'UncompressedQuickTime',
905 Format => 'Int32uData',
906 },
907 0xffff => {
908 Name => 'Reserved',
909 Format => 'Int32uData',
910 },
911);
912
913# picture comment 'kind' codes
914# http://developer.apple.com/technotes/qd/qd_10.html
915my %commentKind = (
916 150 => 'TextBegin',
917 151 => 'TextEnd',
918 152 => 'StringBegin',
919 153 => 'StringEnd',
920 154 => 'TextCenter',
921 155 => 'LineLayoutOff',
922 156 => 'LineLayoutOn',
923 157 => 'ClientLineLayout',
924 160 => 'PolyBegin',
925 161 => 'PolyEnd',
926 163 => 'PolyIgnore',
927 164 => 'PolySmooth',
928 165 => 'PolyClose',
929 180 => 'DashedLine',
930 181 => 'DashedStop',
931 182 => 'SetLineWidth',
932 190 => 'PostScriptBegin',
933 191 => 'PostScriptEnd',
934 192 => 'PostScriptHandle',
935 193 => 'PostScriptFile',
936 194 => 'TextIsPostScript',
937 195 => 'ResourcePS',
938 196 => 'PSBeginNoSave',
939 197 => 'SetGrayLevel',
940 200 => 'RotateBegin',
941 201 => 'RotateEnd',
942 202 => 'RotateCenter',
943 210 => 'FormsPrinting',
944 211 => 'EndFormsPrinting',
945 224 => '<ICC Profile>',
946 498 => '<Photoshop Data>',
947 1000 => 'BitMapThinningOff',
948 1001 => 'BitMapThinningOn',
949);
950
951#------------------------------------------------------------------------------
952# Get PixData data
953# Inputs: 0) reference to PixMap, 1) RAF reference
954# Returns: reference to PixData or undef on error
955sub GetPixData($$)
956{
957 my ($pixMap, $raf) = @_;
958 my $packType = $pixMap->{packType};
959 my $rowBytes = $pixMap->{rowBytes} & 0x3fff; # remove flags bits
960 my $height = $pixMap->{bounds}->{botRight}->{v} -
961 $pixMap->{bounds}->{topLeft}->{v};
962 my ($data, $size, $buff, $i);
963
964 if ($packType == 1 or $rowBytes < 8) { # unpacked data
965 $size = $rowBytes * $height;
966 return undef unless $raf->Read($data, $size) == $size;
967 } elsif ($packType == 2) { # pad byte dropped
968 $size = int($rowBytes * $height * 3 / 4 + 0.5);
969 return undef unless $raf->Read($data, $size) == $size;
970 } else {
971 $data = '';
972 for ($i=0; $i<$height; ++$i) {
973 if ($rowBytes > 250) {
974 $raf->Read($buff,2) == 2 or return undef;
975 $size = unpack('n',$buff);
976 } else {
977 $raf->Read($buff,1) == 1 or return undef;
978 $size = unpack('C',$buff);
979 }
980 $data .= $buff;
981 $raf->Read($buff,$size) == $size or return undef;
982 $data .= $buff;
983 }
984 }
985 return \$data;
986}
987
988#------------------------------------------------------------------------------
989# Read value from PICT file
990# Inputs: 0) RAF reference, 1) tag, 2) format, 3) optional count
991# Returns: value, reference to structure hash, or undef on error
992sub ReadPictValue($$$;$)
993{
994 my ($raf, $tag, $format, $count) = @_;
995 return undef unless $format;
996 unless (defined $count) {
997 if ($format =~ /(.+)\[(.+)\]/s) {
998 $format = $1;
999 $count = $2;
1000 } else {
1001 $count = 1; # count undefined: assume 1
1002 }
1003 }
1004 my $cntStr = ($count == 1) ? '' : "[$count]";
1005 # no size if count is 0
1006 my $size = $count ? Image::ExifTool::FormatSize($format) : 0;
1007 if (defined $size or $format eq 'null') {
1008 my $val;
1009 if ($size) {
1010 my $buff;
1011 $size *= $count;
1012 $raf->Read($buff, $size) == $size or return undef;
1013 $val = ReadValue(\$buff, 0, $format, $count, $size);
1014 } else {
1015 $val = '';
1016 }
1017 if ($verbose) {
1018 print $out "${indent}$tag ($format$cntStr)";
1019 if ($size) {
1020 if (not defined $val) {
1021 print $out " = <undef>\n";
1022 } elsif ($format eq 'binary') {
1023 print $out " = <binary data>\n";
1024 if ($verbose > 2) {
1025 my %parms = ( Out => $out );
1026 $parms{MaxLen} = 96 if $verbose < 4;
1027 Image::ExifTool::HexDump(\$val, undef, %parms);
1028 }
1029 } else {
1030 print $out " = $val\n";
1031 }
1032 } else {
1033 print $out "\n";
1034 }
1035 }
1036 return \$val if $format eq 'binary' and defined $val;
1037 return $val;
1038 }
1039 $verbose and print $out "${indent}$tag ($format$cntStr):\n";
1040 my $struct = $structs{$format} or return undef;
1041 my ($c, @vals);
1042 for ($c=0; $c<$count; ++$c) {
1043 my (%val, $i);
1044 for ($i=0; ; $i+=2) {
1045 my $tag = $$struct[$i] or last;
1046 my $fmt = $$struct[$i+1];
1047 my ($cnt, $val);
1048 $indent .= ' ';
1049 if (ref $fmt) {
1050 $val = eval $$fmt;
1051 $@ and warn $@;
1052 if ($verbose and defined $val) {
1053 printf $out "${indent}$tag (binary[%d]) = <binary data>\n",length($$val);
1054 if ($verbose > 2) {
1055 my %parms = ( Out => $out );
1056 $parms{MaxLen} = 96 if $verbose < 4;
1057 Image::ExifTool::HexDump($val, undef, %parms);
1058 }
1059 }
1060 } elsif ($fmt =~ /(.+)\[(.+)\]/s) {
1061 $fmt = $1;
1062 $cnt = eval $2;
1063 $@ and warn $@;
1064 $val = ReadPictValue($raf, $tag, $fmt, $cnt);
1065 } else {
1066 $val = ReadPictValue($raf, $tag, $fmt);
1067 }
1068 $indent = substr($indent, 2);
1069 return undef unless defined $val;
1070 $val{$tag} = $val;
1071 }
1072 return \%val if $count == 1;
1073 push @vals, \%val;
1074 }
1075 return \@vals;
1076}
1077
1078#------------------------------------------------------------------------------
1079# Extract meta information from a PICT image
1080# Inputs: 0) ExifTool object reference, 1) dirInfo reference
1081# Returns: 1 on success, 0 if this wasn't a valid PICT image
1082sub ProcessPICT($$)
1083{
1084 my ($exifTool, $dirInfo) = @_;
1085 my $raf = $$dirInfo{RAF};
1086 $verbose = $exifTool->Options('Verbose');
1087 $out = $exifTool->Options('TextOut');
1088 $indent = '';
1089 my ($buff, $tried, @hdr, $op, $hRes, $vRes);
1090
1091 # recognize both PICT files and PICT resources (PICT files have a
1092 # 512-byte header that we ignore, but PICT resources do not)
1093 for (;;) {
1094 $raf->Read($buff, 12) == 12 or return 0;
1095 @hdr = unpack('x2n5', $buff);
1096 $op = pop @hdr;
1097 # check for PICT version 1 format
1098 if ($op eq 0x1101) {
1099 $vers = 1;
1100 undef $extended;
1101 last;
1102 }
1103 # check for PICT version 2 format
1104 if ($op eq 0x0011) {
1105 $raf->Read($buff, 28) == 28 or return 0;
1106 if ($buff =~ /^\x02\xff\x0c\x00\xff\xff/) {
1107 $vers = 2;
1108 undef $extended;
1109 last;
1110 }
1111 if ($buff =~ /^\x02\xff\x0c\x00\xff\xfe/) {
1112 $vers = 2;
1113 $extended = 1;
1114 ($hRes, $vRes) = unpack('x8N2', $buff);
1115 last;
1116 }
1117 }
1118 return 0 if $tried;
1119 $tried = 1;
1120 $raf->Seek(512, 0) or return 0;
1121 }
1122 # make the bounding rect signed
1123 foreach (@hdr) {
1124 $_ >= 0x8000 and $_ -= 0x10000;
1125 }
1126 my $w = $hdr[3] - $hdr[1];
1127 my $h = $hdr[2] - $hdr[0];
1128 return 0 unless $w > 0 and $h > 0;
1129
1130 SetByteOrder('MM');
1131
1132 if ($extended) {
1133 # extended version 2 pictures contain resolution information
1134 # and image bounds are in 72-dpi equivalent units
1135 $hRes = GetFixed32s(\$buff, 8);
1136 $vRes = GetFixed32s(\$buff, 12);
1137 return 0 unless $hRes and $vRes;
1138 $w = int($w * $hRes / 72 + 0.5);
1139 $h = int($h * $vRes / 72 + 0.5);
1140 }
1141 $exifTool->SetFileType();
1142 $exifTool->FoundTag('ImageWidth', $w);
1143 $exifTool->FoundTag('ImageHeight', $h);
1144 $exifTool->FoundTag('XResolution', $hRes) if $hRes;
1145 $exifTool->FoundTag('YResolution', $vRes) if $vRes;
1146
1147 # don't extract image opcodes unless verbose
1148 return 1 unless $verbose or $exifTool->Options('Unknown');
1149
1150 $verbose and printf $out "PICT version $vers%s\n", $extended ? ' extended' : '';
1151
1152 my $tagTablePtr = GetTagTable('Image::ExifTool::PICT::Main');
1153
1154 my $success;
1155 for (;;) {
1156 if ($vers == 1) {
1157 $raf->Read($buff, 1) == 1 or last;
1158 $op = ord($buff);
1159 } else {
1160 # must start version 2 opcode on an even byte
1161 $raf->Read($buff, 1) if $raf->Tell() & 0x01;
1162 $raf->Read($buff, 2) == 2 or last;
1163 $op = unpack('n', $buff);
1164 }
1165 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $op);
1166 unless ($tagInfo) {
1167 my $i;
1168 # search for reserved tag info
1169 for ($i=0; $i<scalar(@reserved); $i+=2) {
1170 next unless $op >= $reserved[$i];
1171 last if $op > $reserved[$i+1];
1172 $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $reserved[$i]);
1173 last;
1174 }
1175 last unless $tagInfo;
1176 }
1177 if ($op eq 0xff) {
1178 $verbose and print $out "End of picture\n";
1179 $success = 1;
1180 last;
1181 }
1182 my $format = $$tagInfo{Format};
1183 unless ($format) {
1184 $exifTool->Warn("Missing format for $$tagInfo{Name}");
1185 last;
1186 }
1187 # replace version number for version-dependent formats
1188 $format =~ s/#$/$vers/;
1189 my $wid = $vers * 2;
1190 $verbose and printf $out "Tag 0x%.${wid}x, ", $op;
1191 my $val = ReadPictValue($raf, $$tagInfo{Name}, $format);
1192 unless (defined $val) {
1193 $exifTool->Warn("Error reading $$tagInfo{Name} information");
1194 last;
1195 }
1196 if (ref $val eq 'HASH') {
1197 # extract JPEG image from CompressedQuickTime imageData
1198 if ($$tagInfo{Name} eq 'CompressedQuickTime' and
1199 ref $val->{imageDescr} eq 'HASH' and
1200 $val->{imageDescr}->{compressor} and
1201 $val->{imageDescr}->{compressor} eq 'Photo - JPEG' and
1202 ref $val->{imageData} eq 'SCALAR' and
1203 $exifTool->ValidateImage($val->{imageData}, 'PreviewImage'))
1204 {
1205 $exifTool->FoundTag('PreviewImage', $val->{imageData});
1206 }
1207 } else {
1208 # $exifTool->FoundTag($tagInfo, $val);
1209 }
1210 }
1211 $success or $exifTool->Warn('End of picture not found');
1212 return 1;
1213}
1214
12151; # end
1216
1217__END__
1218
1219=head1 NAME
1220
1221Image::ExifTool::PICT - Read PICT meta information
1222
1223=head1 SYNOPSIS
1224
1225This module is used by Image::ExifTool
1226
1227=head1 DESCRIPTION
1228
1229This module contains routines required by Image::ExifTool to read PICT
1230(Apple Picture) images.
1231
1232=head1 NOTES
1233
1234Extraction of PICT opcodes is experimental, and is only enabled with the
1235Verbose or the Unknown option.
1236
1237=head1 AUTHOR
1238
1239Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
1240
1241This library is free software; you can redistribute it and/or modify it
1242under the same terms as Perl itself.
1243
1244=head1 REFERENCES
1245
1246=over 4
1247
1248=item L<http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-2.html>
1249
1250=item L<http://developer.apple.com/documentation/QuickTime/INMAC/QT/iqImageCompMgr.a.htm>
1251
1252=back
1253
1254=head1 SEE ALSO
1255
1256L<Image::ExifTool::TagNames/PICT Tags>,
1257L<Image::ExifTool(3pm)|Image::ExifTool>
1258
1259=cut
1260
Note: See TracBrowser for help on using the repository browser.