File Coverage

blib/lib/Image/ExifTool/PhotoCD.pm
Criterion Covered Total %
statement 18 18 100.0
branch 2 2 100.0
condition 4 6 66.6
subroutine 4 4 100.0
pod 0 1 0.0
total 28 31 90.3


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: PhotoCD.pm
3             #
4             # Description: Read Kodak Photo CD Image Pac (PCD) metadata
5             #
6             # Revisions: 2012/05/07 - P. Harvey Created
7             #
8             # References: 1) http://pcdtojpeg.sourceforge.net/
9             #------------------------------------------------------------------------------
10              
11             package Image::ExifTool::PhotoCD;
12              
13 4     4   4553 use strict;
  4         14  
  4         139  
14 4     4   24 use vars qw($VERSION);
  4         15  
  4         168  
15 4     4   23 use Image::ExifTool qw(:DataAccess :Utils);
  4         17  
  4         4526  
16              
17             $VERSION = '1.03';
18              
19             sub ProcessExtData($$$);
20              
21             # PhotoCD info
22             %Image::ExifTool::PhotoCD::Main = (
23             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
24             GROUPS => { 2 => 'Image' },
25             NOTES => 'Tags extracted from Kodak Photo CD Image Pac (PCD) files.',
26             7 => {
27             Name => 'SpecificationVersion',
28             Format => 'int8u[2]',
29             RawConv => '$val eq "255 255" ? "n/a" : $val',
30             ValueConv => '$val =~ tr/ /./; $val',
31             },
32             9 => {
33             Name => 'AuthoringSoftwareRelease',
34             Format => 'int8u[2]',
35             RawConv => '$val eq "255 255" ? "n/a" : $val',
36             ValueConv => '$val =~ tr/ /./; $val',
37             },
38             11 => {
39             Name => 'ImageMagnificationDescriptor',
40             Format => 'int8u[2]',
41             ValueConv => '$val =~ tr/ /./; $val',
42             },
43             13 => {
44             Name => 'CreateDate',
45             Format => 'int32u',
46             Groups => { 2 => 'Time' },
47             RawConv => '$val == 0xffffffff ? undef : $val',
48             ValueConv => 'ConvertUnixTime($val,1)',
49             PrintConv => '$self->ConvertDateTime($val)',
50             },
51             17 => {
52             Name => 'ModifyDate',
53             Format => 'int32u',
54             Groups => { 2 => 'Time' },
55             RawConv => '$val == 0xffffffff ? undef : $val',
56             ValueConv => 'ConvertUnixTime($val,1)',
57             PrintConv => '$self->ConvertDateTime($val)',
58             },
59             21 => {
60             Name => 'ImageMedium',
61             PrintConv => {
62             0 => 'Color negative',
63             1 => 'Color reversal',
64             2 => 'Color hard copy',
65             3 => 'Thermal hard copy',
66             4 => 'Black and white negative',
67             5 => 'Black and white reversal',
68             6 => 'Black and white hard copy',
69             7 => 'Internegative',
70             8 => 'Synthetic image',
71             },
72             },
73             22 => {
74             Name => 'ProductType',
75             Format => 'string[20]',
76             ValueConv => '$val =~ s/[ \0]+$//; $val',
77             },
78             42 => {
79             Name => 'ScannerVendorID',
80             Format => 'string[20]',
81             ValueConv => '$val =~ s/[ \0]+$//; $val',
82             },
83             62 => {
84             Name => 'ScannerProductID',
85             Format => 'string[16]',
86             ValueConv => '$val =~ s/[ \0]+$//; $val',
87             },
88             78 => {
89             Name => 'ScannerFirmwareVersion',
90             Format => 'string[4]',
91             ValueConv => '$val =~ s/[ \0]+$//; $val',
92             },
93             82 => {
94             Name => 'ScannerFirmwareDate',
95             Format => 'string[8]',
96             ValueConv => '$val =~ s/[ \0]+$//; $val',
97             },
98             90 => {
99             Name => 'ScannerSerialNumber',
100             Format => 'string[20]',
101             ValueConv => '$val =~ s/[ \0]+$//; $val',
102             },
103             110 => {
104             Name => 'ScannerPixelSize',
105             Format => 'undef[2]',
106             ValueConv => 'join(".",unpack("H2H2",$val))',
107             PrintConv => '"$val micrometers"',
108             },
109             112 => {
110             Name => 'ImageWorkstationMake',
111             Format => 'string[20]',
112             ValueConv => '$val =~ s/[ \0]+$//; $val',
113             },
114             132 => {
115             Name => 'CharacterSet',
116             PrintConv => {
117             1 => '38 characters ISO 646',
118             2 => '65 characters ISO 646',
119             3 => '95 characters ISO 646',
120             4 => '191 characters ISO 8850-1',
121             5 => 'ISO 2022',
122             6 => 'Includes characters not ISO 2375 registered',
123             },
124             },
125             133 => {
126             Name => 'CharacterEscapeSequence',
127             Format => 'undef[32]',
128             Binary => 1,
129             Unknown => 1,
130             },
131             165 => {
132             Name => 'PhotoFinisherName',
133             Format => 'string[60]',
134             ValueConv => '$val =~ s/[ \0]+$//; $val',
135             },
136             225 => {
137             Name => 'HasSBA',
138             Format => 'undef[3]',
139             Hidden => 1,
140             RawConv => '$val eq "SBA" and $$self{HasSBA} = 1; undef',
141             },
142             228 => {
143             Name => 'SceneBalanceAlgorithmRevision',
144             Condition => '$$self{HasSBA}',
145             Format => 'int8u[2]',
146             ValueConv => '$val =~ tr/ /./; $val',
147             },
148             230 => {
149             Name => 'SceneBalanceAlgorithmCommand',
150             Condition => '$$self{HasSBA}',
151             PrintConv => {
152             0 => 'Neutral SBA On, Color SBA On',
153             1 => 'Neutral SBA Off, Color SBA Off',
154             2 => 'Neutral SBA On, Color SBA Off',
155             3 => 'Neutral SBA Off, Color SBA On',
156             },
157             },
158             325 => {
159             Name => 'SceneBalanceAlgorithmFilmID',
160             Condition => '$$self{HasSBA}',
161             Format => 'int16u',
162             PrintConv => {
163             1 => '3M ScotchColor AT 100',
164             2 => '3M ScotchColor AT 200',
165             3 => '3M ScotchColor HR2 400',
166             7 => '3M Scotch HR 200 Gen 2',
167             9 => '3M Scotch HR 400 Gen 2',
168             16 => 'Agfa Agfacolor XRS 400 Gen 1',
169             17 => 'Agfa Agfacolor XRG/XRS 400',
170             18 => 'Agfa Agfacolor XRG/XRS 200',
171             19 => 'Agfa Agfacolor XRS 1000 Gen 2',
172             20 => 'Agfa Agfacolor XRS 400 Gen 2',
173             21 => 'Agfa Agfacolor XRS/XRC 100',
174             26 => 'Fuji Reala 100 (JAPAN)',
175             27 => 'Fuji Reala 100 Gen 1',
176             28 => 'Fuji Reala 100 Gen 2',
177             29 => 'Fuji SHR 400 Gen 2',
178             30 => 'Fuji Super HG 100',
179             31 => 'Fuji Super HG 1600 Gen 1',
180             32 => 'Fuji Super HG 200',
181             33 => 'Fuji Super HG 400',
182             34 => 'Fuji Super HG 100 Gen 2',
183             35 => 'Fuji Super HR 100 Gen 1',
184             36 => 'Fuji Super HR 100 Gen 2',
185             37 => 'Fuji Super HR 1600 Gen 2',
186             38 => 'Fuji Super HR 200 Gen 1',
187             39 => 'Fuji Super HR 200 Gen 2',
188             40 => 'Fuji Super HR 400 Gen 1',
189             43 => 'Fuji NSP 160S (Pro)',
190             45 => 'Kodak Kodacolor VR 100 Gen 2',
191             47 => 'Kodak Gold 400 Gen 3',
192             55 => 'Kodak Ektar 100 Gen 1',
193             56 => 'Kodak Ektar 1000 Gen 1',
194             57 => 'Kodak Ektar 125 Gen 1',
195             58 => 'Kodak Royal Gold 25 RZ',
196             60 => 'Kodak Gold 1600 Gen 1',
197             61 => 'Kodak Gold 200 Gen 2',
198             62 => 'Kodak Gold 400 Gen 2',
199             65 => 'Kodak Kodacolor VR 100 Gen 1',
200             66 => 'Kodak Kodacolor VR 1000 Gen 2',
201             67 => 'Kodak Kodacolor VR 1000 Gen 1',
202             68 => 'Kodak Kodacolor VR 200 Gen 1',
203             69 => 'Kodak Kodacolor VR 400 Gen 1',
204             70 => 'Kodak Kodacolor VR 200 Gen 2',
205             71 => 'Kodak Kodacolor VRG 100 Gen 1',
206             72 => 'Kodak Gold 100 Gen 2',
207             73 => 'Kodak Kodacolor VRG 200 Gen 1',
208             74 => 'Kodak Gold 400 Gen 1',
209             87 => 'Kodak Ektacolor Gold 160',
210             88 => 'Kodak Ektapress 1600 Gen 1 PPC',
211             89 => 'Kodak Ektapress Gold 100 Gen 1 PPA',
212             90 => 'Kodak Ektapress Gold 400 PPB-3',
213             92 => 'Kodak Ektar 25 Professional PHR',
214             97 => 'Kodak T-Max 100 Professional',
215             98 => 'Kodak T-Max 3200 Professional',
216             99 => 'Kodak T-Max 400 Professional',
217             101 => 'Kodak Vericolor 400 Prof VPH',
218             102 => 'Kodak Vericolor III Pro',
219             121 => 'Konika Konica Color SR-G 3200',
220             122 => 'Konika Konica Color Super SR100',
221             123 => 'Konika Konica Color Super SR 400',
222             138 => 'Kodak Gold Unknown',
223             139 => 'Kodak Unknown Neg A- Normal SBA',
224             143 => 'Kodak Ektar 100 Gen 2',
225             147 => 'Kodak Kodacolor CII',
226             148 => 'Kodak Kodacolor II',
227             149 => 'Kodak Gold Plus 200 Gen 3',
228             150 => 'Kodak Internegative +10% Contrast',
229             151 => 'Agfa Agfacolor Ultra 50',
230             152 => 'Fuji NHG 400',
231             153 => 'Agfa Agfacolor XRG 100',
232             154 => 'Kodak Gold Plus 100 Gen 3',
233             155 => 'Konika Konica Color Super SR200 Gen 1',
234             156 => 'Konika Konica Color SR-G 160',
235             157 => 'Agfa Agfacolor Optima 125',
236             158 => 'Agfa Agfacolor Portrait 160',
237             162 => 'Kodak Kodacolor VRG 400 Gen 1',
238             163 => 'Kodak Gold 200 Gen 1',
239             164 => 'Kodak Kodacolor VRG 100 Gen 2',
240             174 => 'Kodak Internegative +20% Contrast',
241             175 => 'Kodak Internegative +30% Contrast',
242             176 => 'Kodak Internegative +40% Contrast',
243             184 => 'Kodak TMax-100 D-76 CI = .40',
244             185 => 'Kodak TMax-100 D-76 CI = .50',
245             186 => 'Kodak TMax-100 D-76 CI = .55',
246             187 => 'Kodak TMax-100 D-76 CI = .70',
247             188 => 'Kodak TMax-100 D-76 CI = .80',
248             189 => 'Kodak TMax-100 TMax CI = .40',
249             190 => 'Kodak TMax-100 TMax CI = .50',
250             191 => 'Kodak TMax-100 TMax CI = .55',
251             192 => 'Kodak TMax-100 TMax CI = .70',
252             193 => 'Kodak TMax-100 TMax CI = .80',
253             195 => 'Kodak TMax-400 D-76 CI = .40',
254             196 => 'Kodak TMax-400 D-76 CI = .50',
255             197 => 'Kodak TMax-400 D-76 CI = .55',
256             198 => 'Kodak TMax-400 D-76 CI = .70',
257             214 => 'Kodak TMax-400 D-76 CI = .80',
258             215 => 'Kodak TMax-400 TMax CI = .40',
259             216 => 'Kodak TMax-400 TMax CI = .50',
260             217 => 'Kodak TMax-400 TMax CI = .55',
261             218 => 'Kodak TMax-400 TMax CI = .70',
262             219 => 'Kodak TMax-400 TMax CI = .80',
263             224 => '3M ScotchColor ATG 400/EXL 400',
264             266 => 'Agfa Agfacolor Optima 200',
265             267 => 'Konika Impressa 50',
266             268 => 'Polaroid Polaroid CP 200',
267             269 => 'Konika Konica Color Super SR200 Gen 2',
268             270 => 'ILFORD XP2 400',
269             271 => 'Polaroid Polaroid Color HD2 100',
270             272 => 'Polaroid Polaroid Color HD2 400',
271             273 => 'Polaroid Polaroid Color HD2 200',
272             282 => '3M ScotchColor ATG-1 200',
273             284 => 'Konika XG 400',
274             307 => 'Kodak Universal Reversal B/W',
275             308 => 'Kodak RPC Copy Film Gen 1',
276             312 => 'Kodak Universal E6',
277             324 => 'Kodak Gold Ultra 400 Gen 4',
278             328 => 'Fuji Super G 100',
279             329 => 'Fuji Super G 200',
280             330 => 'Fuji Super G 400 Gen 2',
281             333 => 'Kodak Universal K14',
282             334 => 'Fuji Super G 400 Gen 1',
283             366 => 'Kodak Vericolor HC 6329 VHC',
284             367 => 'Kodak Vericolor HC 4329 VHC',
285             368 => 'Kodak Vericolor L 6013 VPL',
286             369 => 'Kodak Vericolor L 4013 VPL',
287             418 => 'Kodak Ektacolor Gold II 400 Prof',
288             430 => 'Kodak Royal Gold 1000',
289             431 => 'Kodak Kodacolor VR 200 / 5093',
290             432 => 'Kodak Gold Plus 100 Gen 4',
291             443 => 'Kodak Royal Gold 100',
292             444 => 'Kodak Royal Gold 400',
293             445 => 'Kodak Universal E6 auto-balance',
294             446 => 'Kodak Universal E6 illum. corr.',
295             447 => 'Kodak Universal K14 auto-balance',
296             448 => 'Kodak Universal K14 illum. corr.',
297             449 => 'Kodak Ektar 100 Gen 3 SY',
298             456 => 'Kodak Ektar 25',
299             457 => 'Kodak Ektar 100 Gen 3 CX',
300             458 => 'Kodak Ektapress Plus 100 Prof PJA-1',
301             459 => 'Kodak Ektapress Gold II 100 Prof',
302             460 => 'Kodak Pro 100 PRN',
303             461 => 'Kodak Vericolor HC 100 Prof VHC-2',
304             462 => 'Kodak Prof Color Neg 100',
305             463 => 'Kodak Ektar 1000 Gen 2',
306             464 => 'Kodak Ektapress Plus 1600 Pro PJC-1',
307             465 => 'Kodak Ektapress Gold II 1600 Prof',
308             466 => 'Kodak Super Gold 1600 GF Gen 2',
309             467 => 'Kodak Kodacolor 100 Print Gen 4',
310             468 => 'Kodak Super Gold 100 Gen 4',
311             469 => 'Kodak Gold 100 Gen 4',
312             470 => 'Kodak Gold III 100 Gen 4',
313             471 => 'Kodak Funtime 100 FA',
314             472 => 'Kodak Funtime 200 FB',
315             473 => 'Kodak Kodacolor VR 200 Gen 4',
316             474 => 'Kodak Gold Super 200 Gen 4',
317             475 => 'Kodak Kodacolor 200 Print Gen 4',
318             476 => 'Kodak Super Gold 200 Gen 4',
319             477 => 'Kodak Gold 200 Gen 4',
320             478 => 'Kodak Gold III 200 Gen 4',
321             479 => 'Kodak Gold Ultra 400 Gen 5',
322             480 => 'Kodak Super Gold 400 Gen 5',
323             481 => 'Kodak Gold 400 Gen 5',
324             482 => 'Kodak Gold III 400 Gen 5',
325             483 => 'Kodak Kodacolor 400 Print Gen 5',
326             484 => 'Kodak Ektapress Plus 400 Prof PJB-2',
327             485 => 'Kodak Ektapress Gold II 400 Prof G5',
328             486 => 'Kodak Pro 400 PPF-2',
329             487 => 'Kodak Ektacolor Gold II 400 EGP-4',
330             488 => 'Kodak Ektacolor Gold 400 Prof EGP-4',
331             489 => 'Kodak Ektapress Gold II Multspd PJM',
332             490 => 'Kodak Pro 400 MC PMC',
333             491 => 'Kodak Vericolor 400 Prof VPH-2',
334             492 => 'Kodak Vericolor 400 Plus Prof VPH-2',
335             493 => 'Kodak Unknown Neg Product Code 83',
336             505 => 'Kodak Ektacolor Pro Gold 160 GPX',
337             508 => 'Kodak Royal Gold 200',
338             517 => 'Kodak 4050000000',
339             519 => 'Kodak Gold Plus 100 Gen 5',
340             520 => 'Kodak Gold 800 Gen 1',
341             521 => 'Kodak Gold Super 200 Gen 5',
342             522 => 'Kodak Ektapress Plus 200 Prof',
343             523 => 'Kodak 4050 E6 auto-balance',
344             524 => 'Kodak 4050 E6 ilum. corr.',
345             525 => 'Kodak 4050 K14',
346             526 => 'Kodak 4050 K14 auto-balance',
347             527 => 'Kodak 4050 K14 ilum. corr.',
348             528 => 'Kodak 4050 Reversal B&W',
349             532 => 'Kodak Advantix 200',
350             533 => 'Kodak Advantix 400',
351             534 => 'Kodak Advantix 100',
352             535 => 'Kodak Ektapress Multspd Prof PJM-2',
353             536 => 'Kodak Kodacolor VR 200 Gen 5',
354             537 => 'Kodak Funtime 200 FB Gen 2',
355             538 => 'Kodak Commercial 200',
356             539 => 'Kodak Royal Gold 25 Copystand',
357             540 => 'Kodak Kodacolor DA 100 Gen 5',
358             545 => 'Kodak Kodacolor VR 400 Gen 2',
359             546 => 'Kodak Gold 100 Gen 6',
360             547 => 'Kodak Gold 200 Gen 6',
361             548 => 'Kodak Gold 400 Gen 6',
362             549 => 'Kodak Royal Gold 100 Gen 2',
363             550 => 'Kodak Royal Gold 200 Gen 2',
364             551 => 'Kodak Royal Gold 400 Gen 2',
365             552 => 'Kodak Gold Max 800 Gen 2',
366             554 => 'Kodak 4050 E6 high contrast',
367             555 => 'Kodak 4050 E6 low saturation high contrast',
368             556 => 'Kodak 4050 E6 low saturation',
369             557 => 'Kodak Universal E-6 Low Saturation',
370             558 => 'Kodak T-Max T400 CN',
371             563 => 'Kodak Ektapress PJ100',
372             564 => 'Kodak Ektapress PJ400',
373             565 => 'Kodak Ektapress PJ800',
374             567 => 'Kodak Portra 160NC',
375             568 => 'Kodak Portra 160VC',
376             569 => 'Kodak Portra 400NC',
377             570 => 'Kodak Portra 400VC',
378             575 => 'Kodak Advantix 100-2',
379             576 => 'Kodak Advantix 200-2',
380             577 => 'Kodak Advantix Black & White + 400',
381             578 => 'Kodak Ektapress PJ800-2',
382             },
383             },
384             331 => {
385             Name => 'CopyrightStatus',
386             Condition => '$$self{HasSBA}',
387             RawConv => '$$self{CopyrightStatus} = $val',
388             PrintConv => {
389             1 => 'Restrictions apply',
390             0xff => 'Not specified',
391             },
392             },
393             332 => {
394             Name => 'CopyrightFileName',
395             Condition => '$$self{CopyrightStatus} and $$self{CopyrightStatus} == 1',
396             Format => 'string[12]',
397             ValueConv => '$val =~ s/[ \0]+$//; $val',
398             },
399             1538 => {
400             Name => 'Orientation',
401             Mask => 0x03,
402             RawConv => '$$self{Orient} = $val',
403             PrintConv => {
404             0 => 'Horizontal (normal)',
405             1 => 'Rotate 270 CW',
406             2 => 'Rotate 180',
407             3 => 'Rotate 90 CW',
408             },
409             },
410             1538.1 => {
411             Name => 'ImageWidth',
412             Mask => 0x0c,
413             # 0=Base (768x512), 1=4Base (1536x1024), 2=16Base (3072x2048)
414             ValueConv => '($$self{Orient} & 0x01 ? 512 : 768) * ($val * 2 || 1)',
415             },
416             1538.2 => {
417             Name => 'ImageHeight',
418             Mask => 0x0c,
419             ValueConv => '($$self{Orient} & 0x01 ? 768 : 512) * ($val * 2 || 1)',
420             },
421             1538.3 => {
422             Name => 'CompressionClass',
423             Mask => 0x60,
424             PrintConv => {
425             0 => 'Class 1 - 35mm film; Pictoral hard copy',
426             1 => 'Class 2 - Large format film',
427             2 => 'Class 3 - Text and graphics, high resolution',
428             3 => 'Class 4 - Text and graphics, high dynamic range',
429             },
430             },
431             #1544 => 'InterleaveRatio',
432             #1545 => 'ADPCMResolution',
433             #1546 => {
434             # Name => 'ADPCMMagnificationPanning',
435             # Format => 'int8u[2]',
436             #},
437             #1548 => 'ADPCMMagnificationFactor',
438             #1549 => {
439             # Name => 'ADPCMDisplayOffset',
440             # Format => 'int8u[2]',
441             #},
442             #1551 => 'ADPCMTransitionDescriptor',
443             );
444              
445             #------------------------------------------------------------------------------
446             # Extract information from a PhotoCD image
447             # Inputs: 0) ExifTool object reference, 1) dirInfo reference
448             # Returns: 1 on success, 0 if this wasn't a valid PhotoCD file
449             sub ProcessPCD($$)
450             {
451 9     9 0 44 my ($et, $dirInfo) = @_;
452 9         50 my $raf = $$dirInfo{RAF};
453 9         16 my $buff;
454 9 100 66     38 return 0 unless $raf->Seek(2048, 0) and
      66        
455             $raf->Read($buff, 2048) == 2048 and
456             $buff =~ /^PCD_IPI/;
457 1         6 SetByteOrder('MM');
458 1         6 $et->SetFileType();
459 1         10 my %dirInfo = (
460             DirName => 'PhotoCD',
461             DataPt => \$buff,
462             DataPos => 4096,
463             );
464 1         4 my $tagTablePtr = GetTagTable('Image::ExifTool::PhotoCD::Main');
465 1         9 return $et->ProcessBinaryData(\%dirInfo, $tagTablePtr);
466             }
467              
468             1; # end
469              
470             __END__