source: gs2-extensions/parallel-building/trunk/src/perllib/cpan/Image/ExifTool/Sony.pm@ 24626

Last change on this file since 24626 was 24626, checked in by jmt12, 13 years ago

An (almost) complete copy of the perllib directory from a (circa SEP2011) head checkout from Greenstone 2 trunk - in order to try and make merging in this extension a little easier later on (as there have been some major changes to buildcol.pl commited in the main trunk but not in the x64 branch)

File size: 65.6 KB
Line 
1#------------------------------------------------------------------------------
2# File: Sony.pm
3#
4# Description: Sony EXIF Maker Notes tags
5#
6# Revisions: 04/06/2004 - P. Harvey Created
7#
8# References: 1) http://www.cybercom.net/~dcoffin/dcraw/
9# 2) http://homepage3.nifty.com/kamisaka/makernote/makernote_sony.htm (2006/08/06)
10# 3) Thomas Bodenmann private communication
11# 4) Philippe Devaux private communication (A700)
12# 5) Marcus Holland-Moritz private communication (A700)
13# 6) Andrey Tverdokhleb private communication
14# 7) Rudiger Lange private communication (A700)
15# 8) Igal Milchtaich private communication
16# 9) Michael Reitinger private communication (DSC-TX7)
17# 10) http://www.klingebiel.com/tempest/hd/pmp.html
18# 11 Mike Battilana private communication
19# JD) Jens Duttke private communication
20#------------------------------------------------------------------------------
21
22package Image::ExifTool::Sony;
23
24use strict;
25use vars qw($VERSION);
26use Image::ExifTool qw(:DataAccess :Utils);
27use Image::ExifTool::Exif;
28use Image::ExifTool::Minolta;
29
30$VERSION = '1.50';
31
32sub ProcessSRF($$$);
33sub ProcessSR2($$$);
34sub WriteSR2($$$);
35
36my %sonyLensTypes; # filled in based on Minolta LensType's
37
38# ExposureProgram values (ref PH, mainly decoded from A200)
39my %sonyExposureProgram = (
40 0 => 'Auto', # (same as 'Program AE'?)
41 1 => 'Manual',
42 2 => 'Program AE',
43 3 => 'Aperture-priority AE',
44 4 => 'Shutter speed priority AE',
45 8 => 'Program Shift A', #7
46 9 => 'Program Shift S', #7
47 19 => 'Night Portrait', # (A330)
48 18 => 'Sunset', # (A330)
49 17 => 'Sports', # (A330)
50 21 => 'Macro', # (A330)
51 20 => 'Landscape', # (A330)
52 16 => 'Portrait', # (A330)
53 35 => 'Auto No Flash', # (A330)
54);
55
56my %binaryDataAttrs = (
57 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
58 WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
59 CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
60 WRITABLE => 1,
61 FIRST_ENTRY => 0,
62);
63
64%Image::ExifTool::Sony::Main = (
65 WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
66 CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
67 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
68 0x0102 => { #5/JD
69 Name => 'Quality',
70 Writable => 'int32u',
71 PrintConv => {
72 0 => 'RAW',
73 1 => 'Super Fine',
74 2 => 'Fine',
75 3 => 'Standard',
76 4 => 'Economy',
77 5 => 'Extra Fine',
78 6 => 'RAW + JPEG',
79 7 => 'Compressed RAW',
80 8 => 'Compressed RAW + JPEG',
81 },
82 },
83 0x0104 => { #5/JD
84 Name => 'FlashExposureComp',
85 Description => 'Flash Exposure Compensation',
86 Writable => 'rational64s',
87 },
88 0x0105 => { #5/JD
89 Name => 'Teleconverter',
90 Writable => 'int32u',
91 PrintHex => 1,
92 PrintConv => {
93 0 => 'None',
94 72 => 'Minolta AF 2x APO (D)',
95 80 => 'Minolta AF 2x APO II',
96 136 => 'Minolta AF 1.4x APO (D)',
97 144 => 'Minolta AF 1.4x APO II',
98 },
99 },
100 0x0112 => { #JD
101 Name => 'WhiteBalanceFineTune',
102 Format => 'int32s',
103 Writable => 'int32u',
104 },
105 0x0114 => [ #PH
106 {
107 Name => 'CameraSettings',
108 Condition => '$$self{Model} =~ /DSLR-A(200|230|300|350|700|850|900)\b/',
109 SubDirectory => {
110 TagTable => 'Image::ExifTool::Sony::CameraSettings',
111 ByteOrder => 'BigEndian',
112 },
113 },
114 {
115 Name => 'CameraSettings2',
116 Condition => '$$self{Model} =~ /DSLR-A(330|380)\b/',
117 SubDirectory => {
118 TagTable => 'Image::ExifTool::Sony::CameraSettings2',
119 ByteOrder => 'BigEndian',
120 },
121 },
122 {
123 Name => 'CameraSettingsUnknown',
124 SubDirectory => {
125 TagTable => 'Image::ExifTool::Sony::CameraSettingsUnknown',
126 ByteOrder => 'BigEndian',
127 },
128 },
129 ],
130 0x0115 => { #JD
131 Name => 'WhiteBalance',
132 Writable => 'int32u',
133 PrintHex => 1,
134 PrintConv => {
135 0x00 => 'Auto',
136 0x01 => 'Color Temperature/Color Filter',
137 0x10 => 'Daylight',
138 0x20 => 'Cloudy',
139 0x30 => 'Shade',
140 0x40 => 'Tungsten',
141 0x50 => 'Flash',
142 0x60 => 'Fluorescent',
143 0x70 => 'Custom',
144 },
145 },
146 0x0e00 => {
147 Name => 'PrintIM',
148 Description => 'Print Image Matching',
149 SubDirectory => {
150 TagTable => 'Image::ExifTool::PrintIM::Main',
151 },
152 },
153 # the next 3 tags have a different meaning for some models (with format int32u)
154 0x1000 => { #9 (F88, multi burst mode only)
155 Name => 'MultiBurstMode',
156 Condition => '$format eq "undef"',
157 Notes => 'MultiBurst tags valid only for models with this feature, like the F88',
158 Writable => 'undef',
159 Format => 'int8u',
160 PrintConv => { 0 => 'Off', 1 => 'On' },
161 },
162 0x1001 => { #9 (F88, multi burst mode only)
163 Name => 'MultiBurstImageWidth',
164 Condition => '$format eq "int16u"',
165 Writable => 'int16u',
166 },
167 0x1002 => { #9 (F88, multi burst mode only)
168 Name => 'MultiBurstImageHeight',
169 Condition => '$format eq "int16u"',
170 Writable => 'int16u',
171 },
172 0x1003 => { #9 (TX7, panorama mode only)
173 Name => 'Panorama',
174 SubDirectory => { TagTable => 'Image::ExifTool::Sony::Panorama' },
175 },
176 0x2001 => { #PH (JPEG images from all DSLR's except the A100)
177 Name => 'PreviewImage',
178 Writable => 'undef',
179 DataTag => 'PreviewImage',
180 # Note: the preview data starts with a 32-byte proprietary Sony header
181 WriteCheck => 'return $val=~/^(none|.{32}\xff\xd8\xff)/s ? undef : "Not a valid image"',
182 RawConv => q{
183 return \$val if $val =~ /^Binary/;
184 $val = substr($val,0x20) if length($val) > 0x20;
185 return \$val if $val =~ s/^.(\xd8\xff\xdb)/\xff$1/s;
186 $$self{PreviewError} = 1 unless $val eq 'none';
187 return undef;
188 },
189 # must construct 0x20-byte header which contains length, width and height
190 ValueConvInv => q{
191 return 'none' unless $val;
192 my $e = new Image::ExifTool;
193 my $info = $e->ImageInfo(\$val,'ImageWidth','ImageHeight');
194 return undef unless $$info{ImageWidth} and $$info{ImageHeight};
195 my $size = Set32u($$info{ImageWidth}) . Set32u($$info{ImageHeight});
196 return Set32u(length $val) . $size . ("\0" x 8) . $size . ("\0" x 4) . $val;
197 },
198 },
199 # 0x2002 - probably Sharpness (PH guess)
200 0x2004 => { #PH (NEX-5)
201 Name => 'Contrast',
202 Writable => 'int32s',
203 PrintConv => '$val > 0 ? "+$val" : $val',
204 PrintConvInv => '$val',
205 },
206 0x2005 => { #PH (NEX-5)
207 Name => 'Saturation',
208 Writable => 'int32s',
209 PrintConv => '$val > 0 ? "+$val" : $val',
210 PrintConvInv => '$val',
211 },
212 0x2006 => { #PH
213 Name => 'Sharpness',
214 Writable => 'int32s',
215 PrintConv => '$val > 0 ? "+$val" : $val',
216 PrintConvInv => '$val',
217 },
218 0x2007 => { #PH
219 Name => 'Brightness',
220 Writable => 'int32s',
221 PrintConv => '$val > 0 ? "+$val" : $val',
222 PrintConvInv => '$val',
223 },
224 0x2008 => { #PH
225 Name => 'LongExposureNoiseReduction',
226 Writable => 'int32u',
227 PrintHex => 1,
228 PrintConv => {
229 0 => 'Off',
230 1 => 'On',
231 0xffff0000 => 'Off 2',
232 0xffff0001 => 'On 2',
233 0xffffffff => 'n/a',
234 },
235 },
236 0x2009 => { #PH
237 Name => 'HighISONoiseReduction',
238 Writable => 'int16u',
239 PrintConv => {
240 0 => 'Off',
241 1 => 'Low',
242 2 => 'Normal',
243 3 => 'High',
244 256 => 'Auto',
245 65535 => 'n/a',
246 },
247 },
248 0x200a => { #PH (A550)
249 Name => 'HDR',
250 Writable => 'int32u',
251 PrintHex => 1,
252 PrintConv => {
253 0x0 => 'Off',
254 0x10001 => 'Auto',
255 0x10010 => '1.0 EV', # (NEX_5)
256 0x10011 => '1.5 EV',
257 0x10012 => '2.0 EV',
258 0x10013 => '2.5 EV',
259 0x10014 => '3.0 EV',
260 0x10015 => '3.5 EV',
261 0x10016 => '4.0 EV',
262 0x10017 => '4.5 EV',
263 0x10018 => '5.0 EV',
264 0x10019 => '5.5 EV',
265 0x1001a => '6.0 EV', # (SLT-A55V)
266 },
267 },
268 0x200b => { #PH
269 Name => 'MultiFrameNoiseReduction',
270 Writable => 'int32u',
271 PrintConv => {
272 0 => 'Off',
273 1 => 'On',
274 255 => 'n/a',
275 },
276 },
277 0x3000 => {
278 Name => 'ShotInfo',
279 SubDirectory => {
280 TagTable => 'Image::ExifTool::Sony::ShotInfo',
281 },
282 },
283 # 0x3000: data block that includes DateTimeOriginal string
284 0xb000 => { #8
285 Name => 'FileFormat',
286 Writable => 'int8u',
287 Count => 4,
288 # dynamically set the file type to SR2 because we could have assumed ARW up till now
289 RawConv => q{
290 $self->OverrideFileType($$self{TIFF_TYPE} = 'SR2') if $val eq '1 0 0 0';
291 return $val;
292 },
293 PrintConv => {
294 '0 0 0 2' => 'JPEG',
295 '1 0 0 0' => 'SR2',
296 '2 0 0 0' => 'ARW 1.0',
297 '3 0 0 0' => 'ARW 2.0',
298 '3 1 0 0' => 'ARW 2.1',
299 '3 2 0 0' => 'ARW 2.2', # (NEX-5)
300 # what about cRAW images?
301 },
302 },
303 0xb001 => { # ref http://forums.dpreview.com/forums/read.asp?forum=1037&message=33609644
304 # (ARW and SR2 images only)
305 Name => 'SonyModelID',
306 Writable => 'int16u',
307 PrintConvColumns => 2,
308 PrintConv => {
309 2 => 'DSC-R1',
310 256 => 'DSLR-A100',
311 257 => 'DSLR-A900',
312 258 => 'DSLR-A700',
313 259 => 'DSLR-A200',
314 260 => 'DSLR-A350',
315 261 => 'DSLR-A300',
316 263 => 'DSLR-A380/A390', #PH (A390)
317 264 => 'DSLR-A330',
318 265 => 'DSLR-A230',
319 266 => 'DSLR-A290', #PH
320 269 => 'DSLR-A850',
321 273 => 'DSLR-A550',
322 274 => 'DSLR-A500', #PH
323 275 => 'DSLR-A450', # (http://dev.exiv2.org/issues/show/0000611)
324 278 => 'NEX-5', #PH
325 279 => 'NEX-3', #PH
326 280 => 'SLT-A33', #PH
327 281 => 'SLT-A55V', #PH
328 282 => 'DSLR-A560', #PH
329 283 => 'DSLR-A580', # (http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,2881.0.html)
330 },
331 },
332 0xb020 => { #2
333 Name => 'ColorReproduction',
334 # observed values: None, Standard, Vivid, Real, AdobeRGB - PH
335 Writable => 'string',
336 },
337 0xb021 => { #2
338 Name => 'ColorTemperature',
339 Writable => 'int32u',
340 PrintConv => '$val ? $val : "Auto"',
341 PrintConvInv => '$val=~/Auto/i ? 0 : $val',
342 },
343 0xb022 => { #7
344 Name => 'ColorCompensationFilter',
345 Format => 'int32s',
346 Writable => 'int32u', # (written incorrectly as unsigned by Sony)
347 Notes => 'negative is green, positive is magenta',
348 },
349 0xb023 => { #PH (A100) - (set by mode dial)
350 Name => 'SceneMode',
351 Writable => 'int32u',
352 PrintConv => \%Image::ExifTool::Minolta::minoltaSceneMode,
353 },
354 0xb024 => { #PH (A100)
355 Name => 'ZoneMatching',
356 Writable => 'int32u',
357 PrintConv => {
358 0 => 'ISO Setting Used',
359 1 => 'High Key',
360 2 => 'Low Key',
361 },
362 },
363 0xb025 => { #PH (A100)
364 Name => 'DynamicRangeOptimizer',
365 Writable => 'int32u',
366 PrintConv => {
367 0 => 'Off',
368 1 => 'Standard',
369 2 => 'Advanced Auto',
370 3 => 'Auto', # (A550)
371 8 => 'Advanced Lv1', #JD
372 9 => 'Advanced Lv2', #JD
373 10 => 'Advanced Lv3', #JD
374 11 => 'Advanced Lv4', #JD
375 12 => 'Advanced Lv5', #JD
376 16 => 'Lv1', # (NEX_5)
377 17 => 'Lv2',
378 18 => 'Lv3',
379 19 => 'Lv4',
380 20 => 'Lv5',
381 },
382 },
383 0xb026 => { #PH (A100)
384 Name => 'ImageStabilization',
385 Writable => 'int32u',
386 PrintConv => { 0 => 'Off', 1 => 'On' },
387 },
388 0xb027 => { #2
389 Name => 'LensType',
390 Writable => 'int32u',
391 SeparateTable => 1,
392 PrintConv => \%sonyLensTypes,
393 },
394 0xb028 => { #2
395 # (used by the DSLR-A100)
396 Name => 'MinoltaMakerNote',
397 # must check for zero since apparently a value of zero indicates the IFD doesn't exist
398 # (dumb Sony -- they shouldn't write this tag if the IFD is missing!)
399 Condition => '$$valPt ne "\0\0\0\0"',
400 Flags => 'SubIFD',
401 SubDirectory => {
402 TagTable => 'Image::ExifTool::Minolta::Main',
403 Start => '$val',
404 },
405 },
406 0xb029 => { #2 (set by creative style menu)
407 Name => 'ColorMode',
408 Writable => 'int32u',
409 PrintConv => \%Image::ExifTool::Minolta::sonyColorMode,
410 },
411 0xb02b => { #PH (A550 JPEG and A200, A230, A300, A350, A380, A700 and A900 ARW)
412 Name => 'FullImageSize',
413 Writable => 'int32u',
414 Count => 2,
415 # values stored height first, so swap to get "width height"
416 ValueConv => 'join(" ", reverse split(" ", $val))',
417 ValueConvInv => 'join(" ", reverse split(" ", $val))',
418 PrintConv => '$val =~ tr/ /x/; $val',
419 PrintConvInv => '$val =~ tr/x/ /; $val',
420 },
421 0xb02c => { #PH (A550 JPEG and A200, A230, A300, A350, A380, A700 and A900 ARW)
422 Name => 'PreviewImageSize',
423 Writable => 'int32u',
424 Count => 2,
425 ValueConv => 'join(" ", reverse split(" ", $val))',
426 ValueConvInv => 'join(" ", reverse split(" ", $val))',
427 PrintConv => '$val =~ tr/ /x/; $val',
428 PrintConvInv => '$val =~ tr/x/ /; $val',
429 },
430 0xb040 => { #2
431 Name => 'Macro',
432 Writable => 'int16u',
433 RawConv => '$val == 65535 ? undef : $val',
434 PrintConv => {
435 0 => 'Off',
436 1 => 'On',
437 2 => 'Close Focus', #9
438 65535 => 'n/a', #PH (A100)
439 },
440 },
441 0xb041 => { #2
442 Name => 'ExposureMode',
443 Writable => 'int16u',
444 RawConv => '$val == 65535 ? undef : $val',
445 PrintConv => {
446 0 => 'Auto',
447 1 => 'Portrait', #PH (HX1)
448 2 => 'Beach', #9
449 4 => 'Snow', #9
450 5 => 'Landscape',
451 6 => 'Program',
452 7 => 'Aperture Priority',
453 8 => 'Shutter Priority',
454 9 => 'Night Scene / Twilight',#2/9
455 10 => 'Hi-Speed Shutter', #9
456 11 => 'Twilight Portrait', #9
457 12 => 'Soft Snap', #9
458 13 => 'Fireworks', #9
459 14 => 'Smile Shutter', #9 (T200)
460 15 => 'Manual',
461 18 => 'High Sensitivity', #9
462 20 => 'Advanced Sports Shooting', #9
463 29 => 'Underwater', #9
464 33 => 'Gourmet', #9
465 34 => 'Panorama', #PH (HX1)
466 35 => 'Handheld Twilight', #PH (HX1/TX1)
467 36 => 'Anti Motion Blur', #PH (TX1)
468 37 => 'Pet', #9
469 38 => 'Backlight Correction HDR', #9
470 65535 => 'n/a', #PH (A100)
471 },
472 },
473 0xb042 => { #9
474 Name => 'FocusMode',
475 Writable => 'int16u',
476 RawConv => '$val == 65535 ? undef : $val',
477 PrintConv => {
478 1 => 'AF-S', # (called Single-AF by Sony)
479 2 => 'AF-C', # (called Monitor-AF by Sony)
480 4 => 'Permanent-AF', # (TX7)
481 65535 => 'n/a', #PH (A100)
482 },
483 },
484 0xb043 => { #9
485 Name => 'AFMode',
486 Writable => 'int16u',
487 RawConv => '$val == 65535 ? undef : $val',
488 PrintConv => {
489 0 => 'Default', # (takes this value after camera reset, but can't be set back once changed)
490 1 => 'Multi AF',
491 2 => 'Center AF',
492 3 => 'Spot AF',
493 4 => 'Flexible Spot AF', # (T200)
494 6 => 'Touch AF',
495 14 => 'Manual Focus', # (T200)
496 15 => 'Face Detected', # (not set when in face detect mode and no faces detected)
497 65535 => 'n/a', #PH (A100)
498 },
499 },
500 0xb044 => { #9
501 Name => 'AFIlluminator',
502 Writable => 'int16u',
503 RawConv => '$val == 65535 ? undef : $val',
504 PrintConv => {
505 0 => 'Off',
506 1 => 'Auto',
507 65535 => 'n/a', #PH (A100)
508 },
509 },
510 0xb047 => { #2
511 Name => 'Quality',
512 Writable => 'int16u',
513 RawConv => '$val == 65535 ? undef : $val',
514 PrintConv => {
515 0 => 'Normal',
516 1 => 'Fine',
517 65535 => 'n/a', #PH (A100)
518 },
519 },
520 0xb048 => { #9
521 Name => 'FlashLevel',
522 Writable => 'int16s',
523 RawConv => '$val == -1 ? undef : $val',
524 PrintConv => {
525 -32768 => 'Low',
526 -1 => 'n/a', #PH (A100)
527 0 => 'Normal',
528 32767 => 'High',
529 },
530 },
531 0xb049 => { #9
532 Name => 'ReleaseMode',
533 Writable => 'int16u',
534 RawConv => '$val == 65535 ? undef : $val',
535 PrintConv => {
536 0 => 'Normal',
537 2 => 'Burst',
538 5 => 'Exposure Bracketing',
539 6 => 'White Balance Bracketing', # (HX5)
540 65535 => 'n/a', #PH (A100)
541 },
542 },
543 0xb04a => { #9
544 Name => 'SequenceNumber',
545 Notes => 'shot number in continuous burst',
546 Writable => 'int16u',
547 RawConv => '$val == 65535 ? undef : $val',
548 PrintConv => {
549 0 => 'Single',
550 65535 => 'n/a', #PH (A100)
551 OTHER => sub { shift }, # pass all other numbers straight through
552 },
553 },
554 0xb04b => { #2/PH
555 Name => 'Anti-Blur',
556 Writable => 'int16u',
557 RawConv => '$val == 65535 ? undef : $val',
558 PrintConv => {
559 0 => 'Off',
560 1 => 'On (Continuous)', #PH (NC)
561 2 => 'On (Shooting)', #PH (NC)
562 65535 => 'n/a',
563 },
564 },
565 0xb04e => { #2
566 Name => 'LongExposureNoiseReduction',
567 Writable => 'int16u',
568 RawConv => '$val == 65535 ? undef : $val',
569 PrintConv => {
570 0 => 'Off',
571 1 => 'On',
572 65535 => 'n/a', #PH (A100)
573 },
574 },
575 0xb04f => { #PH (TX1)
576 Name => 'DynamicRangeOptimizer',
577 Writable => 'int16u',
578 PrintConv => {
579 0 => 'Off',
580 1 => 'Standard',
581 2 => 'Plus',
582 },
583 },
584 0xb052 => { #PH (TX1)
585 Name => 'IntelligentAuto',
586 Writable => 'int16u',
587 PrintConv => {
588 0 => 'Off',
589 1 => 'On',
590 2 => 'Advanced', #9
591 },
592 },
593 0xb054 => { #PH (TX1)
594 Name => 'WhiteBalance',
595 Writable => 'int16u',
596 Priority => 0, # (until more values are filled in)
597 PrintConv => {
598 0 => 'Auto',
599 4 => 'Manual',
600 5 => 'Daylight',
601 6 => 'Cloudy', #9
602 7 => 'White Flourescent', #9 (Sony "Fluorescent 1 (White)")
603 8 => 'Cool White Flourescent', #9 (Sony "Fluorescent 2 (Natural White)")
604 9 => 'Day White Flourescent', #9 (Sony "Fluorescent 3 (Day White)")
605 14 => 'Incandescent',
606 15 => 'Flash', #9
607 17 => 'Underwater 1 (Blue Water)', #9
608 18 => 'Underwater 2 (Green Water)', #9
609 },
610 },
611);
612
613# "SEMC MS" maker notes
614%Image::ExifTool::Sony::Ericsson = (
615 WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
616 CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
617 GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
618 NOTES => 'Maker notes found in images from some Sony Ericsson phones.',
619 0x2000 => {
620 Name => 'MakerNoteVersion',
621 Writable => 'undef',
622 Count => 4,
623 },
624 0x201 => {
625 Name => 'PreviewImageStart',
626 IsOffset => 1,
627 MakerPreview => 1, # force preview inside maker notes
628 OffsetPair => 0x202,
629 DataTag => 'PreviewImage',
630 Writable => 'int32u',
631 Protected => 2,
632 Notes => 'a small 320x200 preview image',
633 },
634 0x202 => {
635 Name => 'PreviewImageLength',
636 OffsetPair => 0x201,
637 DataTag => 'PreviewImage',
638 Writable => 'int32u',
639 Protected => 2,
640 },
641);
642
643# Camera settings (ref PH) (decoded mainly from A200)
644%Image::ExifTool::Sony::CameraSettings = (
645 %binaryDataAttrs,
646 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
647 FORMAT => 'int16u',
648 NOTES => q{
649 Camera settings for the A200, A230, A300, A350, A700, A850 and A900. Some
650 tags are only valid for certain models.
651 },
652 0x04 => { #7 (A700, not valid for other models)
653 Name => 'DriveMode',
654 Condition => '$$self{Model} =~ /DSLR-A700\b/',
655 Notes => 'A700 only',
656 PrintConv => {
657 1 => 'Single Frame',
658 2 => 'Continuous High',
659 4 => 'Self-timer 10 sec',
660 5 => 'Self-timer 2 sec',
661 7 => 'Continuous Bracketing',
662 12 => 'Continuous Low',
663 18 => 'White Balance Bracketing Low',
664 19 => 'D-Range Optimizer Bracketing Low',
665 },
666 },
667 0x06 => { #7 (A700, not valid for other models)
668 Name => 'WhiteBalanceFineTune',
669 Condition => '$$self{Model} =~ /DSLR-A700\b/',
670 Format => 'int16s',
671 Notes => 'A700 only',
672 },
673 0x10 => { #7 (A700, not confirmed for other models)
674 Name => 'FocusMode',
675 PrintConv => {
676 0 => 'Manual',
677 1 => 'AF-S',
678 2 => 'AF-C',
679 3 => 'AF-A',
680 },
681 },
682 0x11 => { #JD (A700)
683 Name => 'AFAreaMode',
684 PrintConv => {
685 0 => 'Wide',
686 1 => 'Local',
687 2 => 'Spot',
688 },
689 },
690 0x12 => { #7 (A700, not confirmed for other models)
691 Name => 'LocalAFAreaPoint',
692 Format => 'int16u',
693 Condition => '$$self{Model} !~ /DSLR-A230/',
694 PrintConv => {
695 1 => 'Center',
696 2 => 'Top',
697 3 => 'Top-Right',
698 4 => 'Right',
699 5 => 'Bottom-Right',
700 6 => 'Bottom',
701 7 => 'Bottom-Left',
702 8 => 'Left',
703 9 => 'Top-Left',
704 10 => 'Far Right',
705 11 => 'Far Left',
706 # have seen value of 128 for A230, A330, A380 - PH
707 },
708 },
709 0x15 => { #7
710 Name => 'MeteringMode',
711 Condition => '$$self{Model} !~ /DSLR-A230/',
712 PrintConv => {
713 1 => 'Multi-segment',
714 2 => 'Center-weighted Average',
715 4 => 'Spot',
716 },
717 },
718 0x16 => {
719 Name => 'ISOSetting',
720 Condition => '$$self{Model} !~ /DSLR-A230/',
721 # 0 indicates 'Auto' (I think)
722 ValueConv => '$val ? exp(($val/8-6)*log(2))*100 : $val',
723 ValueConvInv => '$val ? 8*(log($val/100)/log(2)+6) : $val',
724 PrintConv => '$val ? sprintf("%.0f",$val) : "Auto"',
725 PrintConvInv => '$val =~ /auto/i ? 0 : $val',
726 },
727 0x18 => { #7
728 Name => 'DynamicRangeOptimizerMode',
729 Condition => '$$self{Model} !~ /DSLR-A230/',
730 PrintConv => {
731 0 => 'Off',
732 1 => 'Standard',
733 2 => 'Advanced Auto',
734 3 => 'Advanced Level',
735 4097 => 'Auto', #PH (A550)
736 },
737 },
738 0x19 => { #7
739 Name => 'DynamicRangeOptimizerLevel',
740 Condition => '$$self{Model} !~ /DSLR-A230/',
741 },
742 0x1a => { # style actually used (combination of mode dial + creative style menu)
743 Name => 'CreativeStyle',
744 Condition => '$$self{Model} !~ /DSLR-A230/',
745 PrintConv => {
746 1 => 'Standard',
747 2 => 'Vivid',
748 3 => 'Portrait',
749 4 => 'Landscape',
750 5 => 'Sunset',
751 6 => 'Night View/Portrait',
752 8 => 'B&W',
753 9 => 'Adobe RGB', # A900
754 11 => 'Neutral',
755 12 => 'Clear', #7
756 13 => 'Deep', #7
757 14 => 'Light', #7
758 15 => 'Autumn', #7
759 16 => 'Sepia', #7
760 },
761 },
762 0x1c => {
763 Name => 'Sharpness',
764 ValueConv => '$val - 10',
765 ValueConvInv => '$val + 10',
766 PrintConv => '$val > 0 ? "+$val" : $val',
767 PrintConvInv => '$val',
768 },
769 0x1d => {
770 Name => 'Contrast',
771 ValueConv => '$val - 10',
772 ValueConvInv => '$val + 10',
773 PrintConv => '$val > 0 ? "+$val" : $val',
774 PrintConvInv => '$val',
775 },
776 0x1e => {
777 Name => 'Saturation',
778 ValueConv => '$val - 10',
779 ValueConvInv => '$val + 10',
780 PrintConv => '$val > 0 ? "+$val" : $val',
781 PrintConvInv => '$val',
782 },
783 0x1f => { #7
784 Name => 'ZoneMatchingValue',
785 Condition => '$$self{Model} !~ /DSLR-A230/',
786 ValueConv => '$val - 10',
787 ValueConvInv => '$val + 10',
788 PrintConv => '$val > 0 ? "+$val" : $val',
789 PrintConvInv => '$val',
790 },
791 0x22 => { #7
792 Name => 'Brightness',
793 Condition => '$$self{Model} !~ /DSLR-A230/',
794 ValueConv => '$val - 10',
795 ValueConvInv => '$val + 10',
796 PrintConv => '$val > 0 ? "+$val" : $val',
797 PrintConvInv => '$val',
798 },
799 0x23 => {
800 Name => 'FlashMode',
801 PrintConv => {
802 0 => 'ADI',
803 1 => 'TTL',
804 },
805 },
806 0x28 => { #7
807 Name => 'PrioritySetupShutterRelease',
808 Condition => '$$self{Model} =~ /DSLR-A700\b/',
809 Notes => 'A700 only',
810 PrintConv => {
811 0 => 'AF',
812 1 => 'Release',
813 },
814 },
815 0x29 => { #7
816 Name => 'AFIlluminator',
817 Condition => '$$self{Model} =~ /DSLR-A700\b/',
818 Notes => 'A700 only',
819 PrintConv => {
820 0 => 'Auto',
821 1 => 'Off',
822 },
823 },
824 0x2a => { #7
825 Name => 'AFWithShutter',
826 Condition => '$$self{Model} =~ /DSLR-A700\b/',
827 Notes => 'A700 only',
828 PrintConv => { 0 => 'On', 1 => 'Off' },
829 },
830 0x2b => { #7
831 Name => 'LongExposureNoiseReduction',
832 Condition => '$$self{Model} =~ /DSLR-A700\b/',
833 Notes => 'A700 only',
834 PrintConv => { 0 => 'Off', 1 => 'On' },
835 },
836 0x2c => { #7
837 Name => 'HighISONoiseReduction',
838 Condition => '$$self{Model} =~ /DSLR-A700\b/',
839 Notes => 'A700 only',
840 0 => 'Normal',
841 1 => 'Low',
842 2 => 'High',
843 3 => 'Off',
844 },
845 0x2d => { #7
846 Name => 'ImageStyle',
847 Condition => '$$self{Model} =~ /DSLR-A700\b/',
848 Notes => 'A700 only',
849 PrintConv => {
850 1 => 'Standard',
851 2 => 'Vivid',
852 9 => 'Adobe RGB',
853 11 => 'Neutral',
854 129 => 'StyleBox1',
855 130 => 'StyleBox2',
856 131 => 'StyleBox3',
857 },
858 },
859 # 0x2d - A900:1=?,4=?,129=std,130=vivid,131=neutral,132=portrait,133=landscape,134=b&w
860 0x3c => {
861 Name => 'ExposureProgram',
862 Priority => 0,
863 PrintConv => \%sonyExposureProgram,
864 },
865 0x3d => {
866 Name => 'ImageStabilization',
867 PrintConv => { 0 => 'Off', 1 => 'On' },
868 },
869 0x3f => { # (verified for A330/A380)
870 Name => 'Rotation',
871 PrintConv => {
872 0 => 'Horizontal (normal)',
873 1 => 'Rotate 90 CW', #(NC)
874 2 => 'Rotate 270 CW',
875 },
876 },
877 0x54 => {
878 Name => 'SonyImageSize',
879 PrintConv => {
880 1 => 'Large',
881 2 => 'Medium',
882 3 => 'Small',
883 },
884 },
885 0x55 => { #7
886 Name => 'AspectRatio',
887 PrintConv => {
888 1 => '3:2',
889 2 => '16:9',
890 },
891 },
892 0x56 => { #PH/7
893 Name => 'Quality',
894 PrintConv => {
895 0 => 'RAW',
896 2 => 'CRAW',
897 34 => 'RAW + JPEG',
898 35 => 'CRAW + JPEG',
899 16 => 'Extra Fine',
900 32 => 'Fine',
901 48 => 'Standard',
902 },
903 },
904 0x58 => { #7
905 Name => 'ExposureLevelIncrements',
906 PrintConv => {
907 33 => '1/3 EV',
908 50 => '1/2 EV',
909 },
910 },
911);
912
913# Camera settings (ref PH) (A330 and A380)
914%Image::ExifTool::Sony::CameraSettings2 = (
915 %binaryDataAttrs,
916 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
917 FORMAT => 'int16u',
918 NOTES => 'Camera settings for the A330 and A380.',
919 0x10 => { #7 (A700, not confirmed for other models)
920 Name => 'FocusMode',
921 PrintConv => {
922 0 => 'Manual',
923 1 => 'AF-S',
924 2 => 'AF-C',
925 3 => 'AF-A',
926 },
927 },
928 0x11 => { #JD (A700)
929 Name => 'AFAreaMode',
930 PrintConv => {
931 0 => 'Wide',
932 1 => 'Local',
933 2 => 'Spot',
934 },
935 },
936 0x12 => { #7 (A700, not confirmed for other models)
937 Name => 'LocalAFAreaPoint',
938 Format => 'int16u',
939 PrintConv => {
940 1 => 'Center',
941 2 => 'Top',
942 3 => 'Top-Right',
943 4 => 'Right',
944 5 => 'Bottom-Right',
945 6 => 'Bottom',
946 7 => 'Bottom-Left',
947 8 => 'Left',
948 9 => 'Top-Left',
949 10 => 'Far Right',
950 11 => 'Far Left',
951 # see value of 128 for some models
952 },
953 },
954 0x13 => {
955 Name => 'MeteringMode',
956 PrintConv => {
957 1 => 'Multi-segment',
958 2 => 'Center-weighted Average',
959 4 => 'Spot',
960 },
961 },
962 0x14 => { # A330/A380
963 Name => 'ISOSetting',
964 # 0 indicates 'Auto' (?)
965 ValueConv => '$val ? exp(($val/8-6)*log(2))*100 : $val',
966 ValueConvInv => '$val ? 8*(log($val/100)/log(2)+6) : $val',
967 PrintConv => '$val ? sprintf("%.0f",$val) : "Auto"',
968 PrintConvInv => '$val =~ /auto/i ? 0 : $val',
969 },
970 0x16 => {
971 Name => 'DynamicRangeOptimizerMode',
972 PrintConv => {
973 0 => 'Off',
974 1 => 'Standard',
975 2 => 'Advanced Auto',
976 3 => 'Advanced Level',
977 },
978 },
979 0x17 => {
980 Name => 'DynamicRangeOptimizerLevel',
981 },
982 0x18 => { # A380
983 Name => 'CreativeStyle',
984 PrintConv => {
985 1 => 'Standard',
986 2 => 'Vivid',
987 3 => 'Portrait',
988 4 => 'Landscape',
989 5 => 'Sunset',
990 6 => 'Night View/Portrait',
991 8 => 'B&W',
992 9 => 'Adobe RGB',
993 11 => 'Neutral',
994 },
995 },
996 0x19 => {
997 Name => 'Sharpness',
998 ValueConv => '$val - 10',
999 ValueConvInv => '$val + 10',
1000 PrintConv => '$val > 0 ? "+$val" : $val',
1001 PrintConvInv => '$val',
1002 },
1003 0x1a => {
1004 Name => 'Contrast',
1005 ValueConv => '$val - 10',
1006 ValueConvInv => '$val + 10',
1007 PrintConv => '$val > 0 ? "+$val" : $val',
1008 PrintConvInv => '$val',
1009 },
1010 0x1b => {
1011 Name => 'Saturation',
1012 ValueConv => '$val - 10',
1013 ValueConvInv => '$val + 10',
1014 PrintConv => '$val > 0 ? "+$val" : $val',
1015 PrintConvInv => '$val',
1016 },
1017 0x23 => {
1018 Name => 'FlashMode',
1019 PrintConv => {
1020 0 => 'ADI',
1021 1 => 'TTL',
1022 },
1023 },
1024 # 0x27 - also related to CreativeStyle:
1025 # A380:1=std,2=vivid,3=portrait,4=landscape,5=sunset,7=night view,8=b&w
1026 0x3c => {
1027 Name => 'ExposureProgram',
1028 Priority => 0,
1029 PrintConv => \%sonyExposureProgram,
1030 },
1031 0x3f => { # (verified for A330/A380)
1032 Name => 'Rotation',
1033 PrintConv => {
1034 0 => 'Horizontal (normal)',
1035 1 => 'Rotate 90 CW', #(NC)
1036 2 => 'Rotate 270 CW',
1037 },
1038 },
1039 0x54 => {
1040 Name => 'SonyImageSize',
1041 PrintConv => {
1042 1 => 'Large',
1043 2 => 'Medium',
1044 3 => 'Small',
1045 },
1046 },
1047 # 0x56 - something to do with JPEG quality?
1048);
1049
1050# Camera settings for other models
1051%Image::ExifTool::Sony::CameraSettingsUnknown = (
1052 %binaryDataAttrs,
1053 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
1054 FORMAT => 'int16u',
1055);
1056
1057# shot information (ref PH)
1058%Image::ExifTool::Sony::ShotInfo = (
1059 %binaryDataAttrs,
1060 GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
1061 DATAMEMBER => [ 0x02, 0x30, 0x32 ],
1062 IS_SUBDIR => [ 0x48, 0x5e ],
1063 # 0x00 - byte order 'II'
1064 0x02 => {
1065 Name => 'FaceInfoOffset',
1066 Format => 'int16u',
1067 DataMember => 'FaceInfoOffset',
1068 Writable => 0,
1069 RawConv => '$$self{FaceInfoOffset} = $val',
1070 },
1071 0x06 => {
1072 Name => 'SonyDateTime',
1073 Format => 'string[20]',
1074 Groups => { 2 => 'Time' },
1075 Shift => 'Time',
1076 PrintConv => '$self->ConvertDateTime($val)',
1077 PrintConvInv => '$self->InverseDateTime($val,0)',
1078 },
1079 0x30 => { #Jeffrey Friedl
1080 Name => 'FacesDetected',
1081 DataMember => 'FacesDetected',
1082 Format => 'int16u',
1083 RawConv => '$$self{FacesDetected} = $val',
1084 },
1085 0x32 => {
1086 Name => 'FaceInfoLength', # length of a single FaceInfo entry
1087 DataMember => 'FaceInfoLength',
1088 Format => 'int16u',
1089 Writable => 0,
1090 RawConv => '$$self{FaceInfoLength} = $val',
1091 },
1092 #0x34 => {
1093 # # values: 'DC5303320222000', 'DC6303320222000' or 'DC7303320222000'
1094 # Name => 'UnknownString',
1095 # Format => 'string[16]',
1096 # Unknown => 1,
1097 #},
1098 0x48 => { # (most models: DC5303320222000 and DC6303320222000)
1099 Name => 'FaceInfo1',
1100 Condition => q{
1101 $$self{FacesDetected} and
1102 $$self{FaceInfoOffset} == 0x48 and
1103 $$self{FaceInfoLength} == 0x20
1104 },
1105 SubDirectory => { TagTable => 'Image::ExifTool::Sony::FaceInfo1' },
1106 },
1107 0x5e => { # (HX7V: DC7303320222000)
1108 Name => 'FaceInfo2',
1109 Condition => q{
1110 $$self{FacesDetected} and
1111 $$self{FaceInfoOffset} == 0x5e and
1112 $$self{FaceInfoLength} == 0x25
1113 },
1114 SubDirectory => { TagTable => 'Image::ExifTool::Sony::FaceInfo2' },
1115 },
1116);
1117
1118%Image::ExifTool::Sony::FaceInfo1 = (
1119 %binaryDataAttrs,
1120 GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
1121 0x00 => {
1122 Name => 'Face1Position',
1123 Format => 'int16u[4]',
1124 RawConv => '$$self{FacesDetected} < 1 ? undef : $val',
1125 Notes => q{
1126 top, left, height and width of detected face. Coordinates are relative to
1127 the full-sized unrotated image, with increasing Y downwards
1128 },
1129 },
1130 0x20 => {
1131 Name => 'Face2Position',
1132 Format => 'int16u[4]',
1133 RawConv => '$$self{FacesDetected} < 2 ? undef : $val',
1134 },
1135 0x40 => {
1136 Name => 'Face3Position',
1137 Format => 'int16u[4]',
1138 RawConv => '$$self{FacesDetected} < 3 ? undef : $val',
1139 },
1140 0x60 => {
1141 Name => 'Face4Position',
1142 Format => 'int16u[4]',
1143 RawConv => '$$self{FacesDetected} < 4 ? undef : $val',
1144 },
1145 0x80 => {
1146 Name => 'Face5Position',
1147 Format => 'int16u[4]',
1148 RawConv => '$$self{FacesDetected} < 5 ? undef : $val',
1149 },
1150 0xa0 => {
1151 Name => 'Face6Position',
1152 Format => 'int16u[4]',
1153 RawConv => '$$self{FacesDetected} < 6 ? undef : $val',
1154 },
1155 0xc0 => {
1156 Name => 'Face7Position',
1157 Format => 'int16u[4]',
1158 RawConv => '$$self{FacesDetected} < 7 ? undef : $val',
1159 },
1160 0xe0 => {
1161 Name => 'Face8Position',
1162 Format => 'int16u[4]',
1163 RawConv => '$$self{FacesDetected} < 8 ? undef : $val',
1164 },
1165);
1166
1167%Image::ExifTool::Sony::FaceInfo2 = (
1168 %binaryDataAttrs,
1169 GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
1170 0x00 => {
1171 Name => 'Face1Position',
1172 Format => 'int16u[4]',
1173 RawConv => '$$self{FacesDetected} < 1 ? undef : $val',
1174 Notes => q{
1175 top, left, height and width of detected face. Coordinates are relative to
1176 the full-sized unrotated image, with increasing Y downwards
1177 },
1178 },
1179 0x25 => {
1180 Name => 'Face2Position',
1181 Format => 'int16u[4]',
1182 RawConv => '$$self{FacesDetected} < 2 ? undef : $val',
1183 },
1184 0x4a => {
1185 Name => 'Face3Position',
1186 Format => 'int16u[4]',
1187 RawConv => '$$self{FacesDetected} < 3 ? undef : $val',
1188 },
1189 0x6f => {
1190 Name => 'Face4Position',
1191 Format => 'int16u[4]',
1192 RawConv => '$$self{FacesDetected} < 4 ? undef : $val',
1193 },
1194 0x94 => {
1195 Name => 'Face5Position',
1196 Format => 'int16u[4]',
1197 RawConv => '$$self{FacesDetected} < 5 ? undef : $val',
1198 },
1199 0xb9 => {
1200 Name => 'Face6Position',
1201 Format => 'int16u[4]',
1202 RawConv => '$$self{FacesDetected} < 6 ? undef : $val',
1203 },
1204 0xde => {
1205 Name => 'Face7Position',
1206 Format => 'int16u[4]',
1207 RawConv => '$$self{FacesDetected} < 7 ? undef : $val',
1208 },
1209 0x103 => {
1210 Name => 'Face8Position',
1211 Format => 'int16u[4]',
1212 RawConv => '$$self{FacesDetected} < 8 ? undef : $val',
1213 },
1214);
1215
1216# panorama info for cameras such as the HX1, HX5, TX7 (ref 9/PH)
1217%Image::ExifTool::Sony::Panorama = (
1218 %binaryDataAttrs,
1219 GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
1220 FORMAT => 'int32u',
1221 NOTES => q{
1222 Tags found only in panorama images from Sony cameras such as the HX1, HX5
1223 and TX7. The width/height values of these tags are not affected by camera
1224 rotation -- the width is always the longer dimension.
1225 },
1226 # 0: 257
1227 1 => 'PanoramaFullWidth', # (including black/grey borders)
1228 2 => 'PanoramaFullHeight',
1229 3 => {
1230 Name => 'PanoramaDirection',
1231 PrintConv => {
1232 0 => 'Right to Left',
1233 1 => 'Left to Right',
1234 },
1235 },
1236 # crop area to remove black/grey borders from full image
1237 4 => 'PanoramaCropLeft',
1238 5 => 'PanoramaCropTop', #PH guess (NC)
1239 6 => 'PanoramaCropRight',
1240 7 => 'PanoramaCropBottom',
1241 # 8: 1728 (HX1), 1824 (HX5/TX7) (value8/value9 = 16/9)
1242 8 => 'PanoramaFrameWidth', #PH guess (NC)
1243 # 9: 972 (HX1), 1026 (HX5/TX7)
1244 9 => 'PanoramaFrameHeight', #PH guess (NC)
1245 # 10: 3200-3800 (HX1), 4000-4900 (HX5/TX7)
1246 10 => 'PanoramaSourceWidth', #PH guess (NC)
1247 # 11: 800-1800 (larger for taller panoramas)
1248 11 => 'PanoramaSourceHeight', #PH guess (NC)
1249 # 12-15: 0
1250);
1251
1252# tag table for SRF0 IFD (ref 1)
1253%Image::ExifTool::Sony::SRF = (
1254 PROCESS_PROC => \&ProcessSRF,
1255 GROUPS => { 0 => 'MakerNotes', 1 => 'SRF#', 2 => 'Camera' },
1256 NOTES => q{
1257 The maker notes in SRF (Sony Raw Format) images contain 7 IFD's with family
1258 1 group names SRF0 through SRF6. SRF0 and SRF1 use the tags in this table,
1259 while SRF2 through SRF5 use the tags in the next table, and SRF6 uses
1260 standard EXIF tags. All information other than SRF0 is encrypted, but
1261 thanks to Dave Coffin the decryption algorithm is known. SRF images are
1262 written by the Sony DSC-F828 and DSC-V3.
1263 },
1264 # tags 0-1 are used in SRF1
1265 0 => {
1266 Name => 'SRF2Key',
1267 Notes => 'key to decrypt maker notes from the start of SRF2',
1268 RawConv => '$self->{SRF2Key} = $val',
1269 },
1270 1 => {
1271 Name => 'DataKey',
1272 Notes => 'key to decrypt the rest of the file from the end of the maker notes',
1273 RawConv => '$self->{SRFDataKey} = $val',
1274 },
1275 # SRF0 contains a single unknown tag with TagID 0x0003
1276);
1277
1278# tag table for Sony RAW Format (ref 1)
1279%Image::ExifTool::Sony::SRF2 = (
1280 PROCESS_PROC => \&ProcessSRF,
1281 GROUPS => { 0 => 'MakerNotes', 1 => 'SRF#', 2 => 'Camera' },
1282 NOTES => "These tags are found in the SRF2 through SRF5 IFD's.",
1283 # the following tags are used in SRF2-5
1284 2 => 'SRF6Offset', #PH
1285 # SRFDataOffset references 2220 bytes of unknown data for the DSC-F828 - PH
1286 3 => { Name => 'SRFDataOffset', Unknown => 1 }, #PH
1287 4 => { Name => 'RawDataOffset' }, #PH
1288 5 => { Name => 'RawDataLength' }, #PH
1289);
1290
1291# tag table for Sony RAW 2 Format Private IFD (ref 1)
1292%Image::ExifTool::Sony::SR2Private = (
1293 PROCESS_PROC => \&ProcessSR2,
1294 WRITE_PROC => \&WriteSR2,
1295 GROUPS => { 0 => 'MakerNotes', 1 => 'SR2', 2 => 'Camera' },
1296 NOTES => q{
1297 The SR2 format uses the DNGPrivateData tag to reference a private IFD
1298 containing these tags. SR2 images are written by the Sony DSC-R1, but
1299 this information is also written to ARW images by other models.
1300 },
1301 0x7200 => {
1302 Name => 'SR2SubIFDOffset',
1303 # (adjusting offset messes up calculations for AdobeSR2 in DNG images)
1304 # Flags => 'IsOffset',
1305 # (can't set OffsetPair or else DataMember won't be set when writing)
1306 # OffsetPair => 0x7201,
1307 DataMember => 'SR2SubIFDOffset',
1308 RawConv => '$$self{SR2SubIFDOffset} = $val',
1309 },
1310 0x7201 => {
1311 Name => 'SR2SubIFDLength',
1312 # (can't set OffsetPair or else DataMember won't be set when writing)
1313 # OffsetPair => 0x7200,
1314 DataMember => 'SR2SubIFDLength',
1315 RawConv => '$$self{SR2SubIFDLength} = $val',
1316 },
1317 0x7221 => {
1318 Name => 'SR2SubIFDKey',
1319 Format => 'int32u',
1320 Notes => 'key to decrypt SR2SubIFD',
1321 DataMember => 'SR2SubIFDKey',
1322 RawConv => '$$self{SR2SubIFDKey} = $val',
1323 PrintConv => 'sprintf("0x%.8x", $val)',
1324 },
1325 0x7240 => { #PH
1326 Name => 'IDC_IFD',
1327 Groups => { 1 => 'SonyIDC' },
1328 Condition => '$$valPt !~ /^\0\0\0\0/', # (just in case this could be zero)
1329 Flags => 'SubIFD',
1330 SubDirectory => {
1331 DirName => 'SonyIDC',
1332 TagTable => 'Image::ExifTool::SonyIDC::Main',
1333 Start => '$val',
1334 },
1335 },
1336 0x7241 => { #PH
1337 Name => 'IDC2_IFD',
1338 Groups => { 1 => 'SonyIDC' },
1339 Condition => '$$valPt !~ /^\0\0\0\0/', # may be zero if dir doesn't exist
1340 Flags => 'SubIFD',
1341 SubDirectory => {
1342 DirName => 'SonyIDC2',
1343 TagTable => 'Image::ExifTool::SonyIDC::Main',
1344 Start => '$val',
1345 Base => '$start',
1346 MaxSubdirs => 20, # (A900 has 10 null entries, but IDC writes only 1)
1347 RelativeBase => 1, # needed to write SubIFD with relative offsets
1348 },
1349 },
1350 0x7250 => { #1
1351 Name => 'MRWInfo',
1352 Condition => '$$valPt !~ /^\0\0\0\0/', # (just in case this could be zero)
1353 SubDirectory => {
1354 TagTable => 'Image::ExifTool::MinoltaRaw::Main',
1355 },
1356 },
1357);
1358
1359%Image::ExifTool::Sony::SR2SubIFD = (
1360 WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
1361 CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
1362 GROUPS => { 0 => 'MakerNotes', 1 => 'SR2SubIFD', 2 => 'Camera' },
1363 SET_GROUP1 => 1, # set group1 name to directory name for all tags in table
1364 NOTES => 'Tags in the encrypted SR2SubIFD',
1365 0x7303 => 'WB_GRBGLevels', #1
1366 0x74c0 => { #PH
1367 Name => 'SR2DataIFD',
1368 Groups => { 1 => 'SR2DataIFD' }, # (needed to set SubIFD DirName)
1369 Flags => 'SubIFD',
1370 SubDirectory => {
1371 TagTable => 'Image::ExifTool::Sony::SR2DataIFD',
1372 Start => '$val',
1373 MaxSubdirs => 20, # an A700 ARW has 14 of these! - PH
1374 },
1375 },
1376 0x7313 => 'WB_RGGBLevels', #6
1377 0x74a0 => 'MaxApertureAtMaxFocal', #PH
1378 0x74a1 => 'MaxApertureAtMinFocal', #PH
1379 0x7820 => 'WB_RGBLevelsDaylight', #6
1380 0x7821 => 'WB_RGBLevelsCloudy', #6
1381 0x7822 => 'WB_RGBLevelsTungsten', #6
1382 0x7825 => 'WB_RGBLevelsShade', #6
1383 0x7826 => 'WB_RGBLevelsFluorescent', #6
1384 0x7828 => 'WB_RGBLevelsFlash', #6
1385);
1386
1387%Image::ExifTool::Sony::SR2DataIFD = (
1388 WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
1389 CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
1390 GROUPS => { 0 => 'MakerNotes', 1 => 'SR2DataIFD', 2 => 'Camera' },
1391 SET_GROUP1 => 1, # set group1 name to directory name for all tags in table
1392 # 0x7313 => 'WB_RGGBLevels', (duplicated in all SR2DataIFD's)
1393 0x7770 => { #PH
1394 Name => 'ColorMode',
1395 Priority => 0,
1396 },
1397);
1398
1399# tags found in DSC-F1 PMP header (ref 10)
1400%Image::ExifTool::Sony::PMP = (
1401 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1402 WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
1403 CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
1404 GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
1405 FIRST_ENTRY => 0,
1406 NOTES => q{
1407 These tags are written in the proprietary-format header of PMP images from
1408 the DSC-F1.
1409 },
1410 8 => { #PH
1411 Name => 'JpgFromRawStart',
1412 Format => 'int32u',
1413 Notes => q{
1414 OK, not really a RAW file, but this mechanism is used to allow extraction of
1415 the JPEG image from a PMP file
1416 },
1417 },
1418 12 => { Name => 'JpgFromRawLength',Format => 'int32u' },
1419 22 => { Name => 'SonyImageWidth', Format => 'int16u' },
1420 24 => { Name => 'SonyImageHeight', Format => 'int16u' },
1421 27 => {
1422 Name => 'Orientation',
1423 PrintConv => {
1424 0 => 'Horizontal (normal)',
1425 1 => 'Rotate 270 CW',#11
1426 2 => 'Rotate 180',
1427 3 => 'Rotate 90 CW',#11
1428 },
1429 },
1430 29 => {
1431 Name => 'ImageQuality',
1432 PrintConv => {
1433 8 => 'Snap Shot',
1434 23 => 'Standard',
1435 51 => 'Fine',
1436 },
1437 },
1438 # 40 => ImageWidth again (int16u)
1439 # 42 => ImageHeight again (int16u)
1440 52 => { Name => 'Comment', Format => 'string[19]' },
1441 76 => {
1442 Name => 'DateTimeOriginal',
1443 Description => 'Date/Time Original',
1444 Format => 'int8u[6]',
1445 Groups => { 2 => 'Time' },
1446 ValueConv => q{
1447 my @a = split ' ', $val;
1448 $a[0] += $a[0] < 70 ? 2000 : 1900;
1449 sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d', @a);
1450 },
1451 PrintConv => '$self->ConvertDateTime($val)',
1452 },
1453 84 => {
1454 Name => 'ModifyDate',
1455 Format => 'int8u[6]',
1456 Groups => { 2 => 'Time' },
1457 ValueConv => q{
1458 my @a = split ' ', $val;
1459 $a[0] += $a[0] < 70 ? 2000 : 1900;
1460 sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d', @a);
1461 },
1462 PrintConv => '$self->ConvertDateTime($val)',
1463 },
1464 102 => {
1465 Name => 'ExposureTime',
1466 Format => 'int16s',
1467 RawConv => '$val <= 0 ? undef : $val',
1468 ValueConv => '2 ** (-$val / 100)',
1469 PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
1470 },
1471 106 => { # (NC -- not written by DSC-F1)
1472 Name => 'FNumber',
1473 Format => 'int16s',
1474 RawConv => '$val <= 0 ? undef : $val',
1475 ValueConv => '$val / 100', # (likely wrong)
1476 },
1477 108 => { # (NC -- not written by DSC-F1)
1478 Name => 'ExposureCompensation',
1479 Format => 'int16s',
1480 RawConv => '($val == -1 or $val == -32768) ? undef : $val',
1481 ValueConv => '$val / 100', # (probably wrong too)
1482 },
1483 112 => { # (NC -- not written by DSC-F1)
1484 Name => 'FocalLength',
1485 Format => 'int16s',
1486 Groups => { 2 => 'Camera' },
1487 RawConv => '$val <= 0 ? undef : $val',
1488 ValueConv => '$val / 100',
1489 PrintConv => 'sprintf("%.1f mm",$val)',
1490 },
1491 118 => {
1492 Name => 'Flash',
1493 Groups => { 2 => 'Camera' },
1494 PrintConv => { 0 => 'No Flash', 1 => 'Fired' },
1495 },
1496);
1497
1498# fill in Sony LensType lookup based on Minolta values
1499{
1500 my $minoltaTypes = \%Image::ExifTool::Minolta::minoltaLensTypes;
1501 %sonyLensTypes = %$minoltaTypes;
1502 my $notes = $$minoltaTypes{Notes};
1503 delete $$minoltaTypes{Notes};
1504 my $id;
1505 foreach $id (sort { $a <=> $b } keys %$minoltaTypes) {
1506 # higher numbered lenses are missing last digit of ID for some Sony models
1507 next if $id < 10000;
1508 my $sid = int($id/10);
1509 my $i;
1510 my $lens = $$minoltaTypes{$id};
1511 if ($sonyLensTypes{$sid}) {
1512 # put lens name with "or" first in list
1513 if ($lens =~ / or /) {
1514 my $tmp = $sonyLensTypes{$sid};
1515 $sonyLensTypes{$sid} = $lens;
1516 $lens = $tmp;
1517 }
1518 for (;;) {
1519 $i = ($i || 0) + 1;
1520 $sid = int($id/10) . ".$i";
1521 last unless $sonyLensTypes{$sid};
1522 }
1523 }
1524 $sonyLensTypes{$sid} = $lens;
1525 }
1526 $$minoltaTypes{Notes} = $sonyLensTypes{Notes} = $notes;
1527}
1528
1529#------------------------------------------------------------------------------
1530# Read Sony DSC-F1 PMP file
1531# Inputs: 0) ExifTool object ref, 1) dirInfo ref
1532# Returns: 1 on success when reading, 0 if this isn't a valid PMP file
1533sub ProcessPMP($$)
1534{
1535 my ($exifTool, $dirInfo) = @_;
1536 my $raf = $$dirInfo{RAF};
1537 my $buff;
1538 $raf->Read($buff, 128) == 128 or return 0;
1539 # validate header length (124 bytes)
1540 $buff =~ /^.{8}\0{3}\x7c.{112}\xff\xd8\xff\xdb$/s or return 0;
1541 $exifTool->SetFileType();
1542 SetByteOrder('MM');
1543 $exifTool->FoundTag(Make => 'Sony');
1544 $exifTool->FoundTag(Model => 'DSC-F1');
1545 # extract information from 124-byte header
1546 my $tagTablePtr = GetTagTable('Image::ExifTool::Sony::PMP');
1547 my %dirInfo = ( DataPt => \$buff, DirName => 'PMP' );
1548 $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);
1549 # process JPEG image
1550 $raf->Seek(124, 0);
1551 $$dirInfo{Base} = 124;
1552 $exifTool->ProcessJPEG($dirInfo);
1553 return 1;
1554}
1555
1556#------------------------------------------------------------------------------
1557# Decrypt Sony data (ref 1)
1558# Inputs: 0) data reference, 1) start offset, 2) data length, 3) decryption key
1559# Returns: nothing (original data buffer is updated with decrypted data)
1560# Notes: data length should be a multiple of 4
1561sub Decrypt($$$$)
1562{
1563 my ($dataPt, $start, $len, $key) = @_;
1564 my ($i, $j, @pad);
1565 my $words = int ($len / 4);
1566
1567 for ($i=0; $i<4; ++$i) {
1568 my $lo = ($key & 0xffff) * 0x0edd + 1;
1569 my $hi = ($key >> 16) * 0x0edd + ($key & 0xffff) * 0x02e9 + ($lo >> 16);
1570 $pad[$i] = $key = (($hi & 0xffff) << 16) + ($lo & 0xffff);
1571 }
1572 $pad[3] = ($pad[3] << 1 | ($pad[0]^$pad[2]) >> 31) & 0xffffffff;
1573 for ($i=4; $i<0x7f; ++$i) {
1574 $pad[$i] = (($pad[$i-4]^$pad[$i-2]) << 1 |
1575 ($pad[$i-3]^$pad[$i-1]) >> 31) & 0xffffffff;
1576 }
1577 my @data = unpack("x$start N$words", $$dataPt);
1578 for ($i=0x7f,$j=0; $j<$words; ++$i,++$j) {
1579 $data[$j] ^= $pad[$i & 0x7f] = $pad[($i+1) & 0x7f] ^ $pad[($i+65) & 0x7f];
1580 }
1581 substr($$dataPt, $start, $words*4) = pack('N*', @data);
1582}
1583
1584#------------------------------------------------------------------------------
1585# Set the ARW file type and decide between SubIFD and A100DataOffset
1586# Inputs: 0) ExifTool object ref, 1) reference to tag 0x14a raw data
1587# Returns: true if tag 0x14a is a SubIFD, false otherwise
1588sub SetARW($$)
1589{
1590 my ($exifTool, $valPt) = @_;
1591
1592 # assume ARW for now -- SR2's get identified when FileFormat is parsed
1593 $exifTool->OverrideFileType($$exifTool{TIFF_TYPE} = 'ARW');
1594
1595 # this should always be a SubIFD for models other than the A100
1596 return 1 unless $$exifTool{Model} eq 'DSLR-A100' and length $$valPt == 4;
1597
1598 # for the A100, IFD0 tag 0x14a is either a pointer to the raw data if this is
1599 # an original image, or a SubIFD offset if the image was edited by Sony IDC,
1600 # so assume it points to the raw data if it isn't a valid IFD (this assumption
1601 # will be checked later when we try to parse the SR2Private directory)
1602 my %subdir = (
1603 DirStart => Get32u($valPt, 0),
1604 Base => 0,
1605 RAF => $$exifTool{RAF},
1606 AllowOutOfOrderTags => 1, # doh!
1607 );
1608 return Image::ExifTool::Exif::ValidateIFD(\%subdir);
1609}
1610
1611#------------------------------------------------------------------------------
1612# Finish writing ARW image, patching necessary Sony quirks, etc
1613# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) EXIF data ref, 3) image data reference
1614# Returns: undef on success, error string otherwise
1615# Notes: (it turns that all of this is for the A100 only)
1616sub FinishARW($$$$)
1617{
1618 my ($exifTool, $dirInfo, $dataPt, $imageData) = @_;
1619
1620 # pre-scan IFD0 to get IFD entry offsets for each tag
1621 my $dataLen = length $$dataPt;
1622 return 'Truncated IFD0' if $dataLen < 2;
1623 my $n = Get16u($dataPt, 0);
1624 return 'Truncated IFD0' if $dataLen < 2 + 12 * $n;
1625 my ($i, %entry, $dataBlock, $pad, $dataOffset);
1626 for ($i=0; $i<$n; ++$i) {
1627 my $entry = 2 + $i * 12;
1628 $entry{Get16u($dataPt, $entry)} = $entry;
1629 }
1630 # fix up SR2Private offset and A100DataOffset (A100 only)
1631 if ($entry{0xc634} and $$exifTool{MRWDirData}) {
1632 return 'Unexpected MRW block' unless $$exifTool{Model} eq 'DSLR-A100';
1633 return 'Missing A100DataOffset' unless $entry{0x14a} and $$exifTool{A100DataOffset};
1634 # account for total length of image data
1635 my $totalLen = 8 + $dataLen;
1636 if (ref $imageData) {
1637 foreach $dataBlock (@$imageData) {
1638 my ($pos, $size, $pad) = @$dataBlock;
1639 $totalLen += $size + $pad;
1640 }
1641 }
1642 # align MRW block on an even 4-byte boundary
1643 my $remain = $totalLen & 0x03;
1644 $pad = 4 - $remain and $totalLen += $pad if $remain;
1645 # set offset for the MRW directory data
1646 Set32u($totalLen, $dataPt, $entry{0xc634} + 8);
1647 # also pad MRWDirData data to an even 4 bytes (just to be safe)
1648 $remain = length($$exifTool{MRWDirData}) & 0x03;
1649 $$exifTool{MRWDirData} .= "\0" x (4 - $remain) if $remain;
1650 $totalLen += length $$exifTool{MRWDirData};
1651 # fix up A100DataOffset
1652 $dataOffset = $$exifTool{A100DataOffset};
1653 Set32u($totalLen, $dataPt, $entry{0x14a} + 8);
1654 }
1655 # patch double-referenced and incorrectly-sized A100 PreviewImage
1656 if ($entry{0x201} and $$exifTool{A100PreviewStart} and
1657 $entry{0x202} and $$exifTool{A100PreviewLength})
1658 {
1659 Set32u($$exifTool{A100PreviewStart}, $dataPt, $entry{0x201} + 8);
1660 Set32u($$exifTool{A100PreviewLength}, $dataPt, $entry{0x202} + 8);
1661 }
1662 # write TIFF IFD structure
1663 my $outfile = $$dirInfo{OutFile};
1664 my $header = GetByteOrder() . Set16u(0x2a) . Set32u(8);
1665 Write($outfile, $header, $$dataPt) or return 'Error writing';
1666 # copy over image data
1667 if (ref $imageData) {
1668 $exifTool->CopyImageData($imageData, $outfile) or return 'Error copying image data';
1669 }
1670 # write MRW data if necessary
1671 if ($$exifTool{MRWDirData}) {
1672 Write($outfile, "\0" x $pad) if $pad; # write padding if necessary
1673 Write($outfile, $$exifTool{MRWDirData});
1674 delete $$exifTool{MRWDirData};
1675 # set TIFF_END to copy over the MRW image data
1676 $$exifTool{TIFF_END} = $dataOffset if $dataOffset;
1677 }
1678 return undef;
1679}
1680
1681#------------------------------------------------------------------------------
1682# Process SRF maker notes
1683# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1684# Returns: 1 on success
1685sub ProcessSRF($$$)
1686{
1687 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
1688 my $dataPt = $$dirInfo{DataPt};
1689 my $start = $$dirInfo{DirStart};
1690 my $verbose = $exifTool->Options('Verbose');
1691
1692 # process IFD chain
1693 my ($ifd, $success);
1694 for ($ifd=0; ; ) {
1695 # switch tag table for SRF2-5 and SRF6
1696 if ($ifd == 2) {
1697 $tagTablePtr = GetTagTable('Image::ExifTool::Sony::SRF2');
1698 } elsif ($ifd == 6) {
1699 # SRF6 uses standard EXIF tags
1700 $tagTablePtr = GetTagTable('Image::ExifTool::Exif::Main');
1701 }
1702 my $srf = $$dirInfo{DirName} = "SRF$ifd";
1703 $exifTool->{SET_GROUP1} = $srf;
1704 $success = Image::ExifTool::Exif::ProcessExif($exifTool, $dirInfo, $tagTablePtr);
1705 delete $exifTool->{SET_GROUP1};
1706 last unless $success;
1707#
1708# get pointer to next IFD
1709#
1710 my $count = Get16u($dataPt, $$dirInfo{DirStart});
1711 my $dirEnd = $$dirInfo{DirStart} + 2 + $count * 12;
1712 last if $dirEnd + 4 > length($$dataPt);
1713 my $nextIFD = Get32u($dataPt, $dirEnd);
1714 last unless $nextIFD;
1715 $nextIFD -= $$dirInfo{DataPos}; # adjust for position of makernotes data
1716 $$dirInfo{DirStart} = $nextIFD;
1717#
1718# decrypt next IFD data if necessary
1719#
1720 ++$ifd;
1721 my ($key, $len);
1722 if ($ifd == 1) {
1723 # get the key to decrypt IFD1
1724 my $cp = $start + 0x8ddc; # why?
1725 my $ip = $cp + 4 * unpack("x$cp C", $$dataPt);
1726 $key = unpack("x$ip N", $$dataPt);
1727 $len = $cp + $nextIFD; # decrypt up to $cp
1728 } elsif ($ifd == 2) {
1729 # get the key to decrypt IFD2
1730 $key = $exifTool->{SRF2Key};
1731 $len = length($$dataPt) - $nextIFD; # decrypt rest of maker notes
1732 } else {
1733 next; # no decryption needed
1734 }
1735 # decrypt data
1736 Decrypt($dataPt, $nextIFD, $len, $key) if defined $key;
1737 next unless $verbose > 2;
1738 # display decrypted data in verbose mode
1739 $exifTool->VerboseDir("Decrypted SRF$ifd", 0, $nextIFD + $len);
1740 $exifTool->VerboseDump($dataPt,
1741 Prefix => "$exifTool->{INDENT} ",
1742 Start => $nextIFD,
1743 DataPos => $$dirInfo{DataPos},
1744 );
1745 }
1746}
1747
1748#------------------------------------------------------------------------------
1749# Write SR2 data
1750# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1751# Returns: 1 on success when reading, or SR2 directory or undef when writing
1752sub WriteSR2($$$)
1753{
1754 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
1755 $exifTool or return 1; # allow dummy access
1756 my $buff = '';
1757 $$dirInfo{OutFile} = \$buff;
1758 return ProcessSR2($exifTool, $dirInfo, $tagTablePtr);
1759}
1760
1761#------------------------------------------------------------------------------
1762# Read/Write SR2 IFD and its encrypted subdirectories
1763# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1764# Returns: 1 on success when reading, or SR2 directory or undef when writing
1765sub ProcessSR2($$$)
1766{
1767 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
1768 my $raf = $$dirInfo{RAF};
1769 my $dataPt = $$dirInfo{DataPt};
1770 my $dataPos = $$dirInfo{DataPos};
1771 my $dataLen = $$dirInfo{DataLen} || length $$dataPt;
1772 my $base = $$dirInfo{Base} || 0;
1773 my $outfile = $$dirInfo{OutFile};
1774
1775 # clear SR2 member variables to be safe
1776 delete $$exifTool{SR2SubIFDOffset};
1777 delete $$exifTool{SR2SubIFDLength};
1778 delete $$exifTool{SR2SubIFDKey};
1779
1780 # make sure we have the first 4 bytes available to test directory type
1781 my $buff;
1782 if ($dataLen < 4 and $raf) {
1783 my $pos = $dataPos + ($$dirInfo{DirStart}||0) + $base;
1784 if ($raf->Seek($pos, 0) and $raf->Read($buff, 4) == 4) {
1785 $dataPt = \$buff;
1786 undef $$dirInfo{DataPt}; # must load data from file
1787 $raf->Seek($pos, 0);
1788 }
1789 }
1790 # this may either be a normal IFD, or a MRW data block
1791 # (only original ARW images from the A100 use the MRW block)
1792 my $dataOffset;
1793 if ($dataPt and $$dataPt =~ /^\0MR[IM]/) {
1794 my ($err, $srfPos, $srfLen, $dataOffset);
1795 $dataOffset = $$exifTool{A100DataOffset};
1796 if ($dataOffset) {
1797 # save information about the RAW data trailer so it will be preserved
1798 $$exifTool{KnownTrailer} = { Name => 'A100 RAW Data', Start => $dataOffset };
1799 } else {
1800 $err = 'A100DataOffset tag is missing from A100 ARW image';
1801 }
1802 $raf or $err = 'Unrecognized SR2 structure';
1803 unless ($err) {
1804 $srfPos = $raf->Tell();
1805 $srfLen = $dataOffset - $srfPos;
1806 unless ($srfLen > 0 and $raf->Read($buff, $srfLen) == $srfLen) {
1807 $err = 'Error reading MRW directory';
1808 }
1809 }
1810 if ($err) {
1811 $outfile and $exifTool->Error($err), return undef;
1812 $exifTool->Warn($err);
1813 return 0;
1814 }
1815 my %dirInfo = ( DataPt => \$buff );
1816 require Image::ExifTool::MinoltaRaw;
1817 if ($outfile) {
1818 # save MRW data to be written last
1819 $$exifTool{MRWDirData} = Image::ExifTool::MinoltaRaw::WriteMRW($exifTool, \%dirInfo);
1820 return $$exifTool{MRWDirData} ? "\0\0\0\0\0\0" : undef;
1821 } else {
1822 if (not $outfile and $$exifTool{HTML_DUMP}) {
1823 $exifTool->HDump($srfPos, $srfLen, '[A100 SRF Data]');
1824 }
1825 return Image::ExifTool::MinoltaRaw::ProcessMRW($exifTool, \%dirInfo);
1826 }
1827 } elsif ($$exifTool{A100DataOffset}) {
1828 my $err = 'Unexpected A100DataOffset tag';
1829 $outfile and $exifTool->Error($err), return undef;
1830 $exifTool->Warn($err);
1831 return 0;
1832 }
1833 my $verbose = $exifTool->Options('Verbose');
1834 my $result;
1835 if ($outfile) {
1836 $result = Image::ExifTool::Exif::WriteExif($exifTool, $dirInfo, $tagTablePtr);
1837 return undef unless $result;
1838 $$outfile .= $result;
1839
1840 } else {
1841 $result = Image::ExifTool::Exif::ProcessExif($exifTool, $dirInfo, $tagTablePtr);
1842 }
1843 return $result unless $result and $$exifTool{SR2SubIFDOffset};
1844 # only take first offset value if more than one!
1845 my @offsets = split ' ', $exifTool->{SR2SubIFDOffset};
1846 my $offset = shift @offsets;
1847 my $length = $exifTool->{SR2SubIFDLength};
1848 my $key = $exifTool->{SR2SubIFDKey};
1849 my @subifdPos;
1850 if ($offset and $length and defined $key) {
1851 my $buff;
1852 # read encrypted SR2SubIFD from file
1853 if (($raf and $raf->Seek($offset+$base, 0) and
1854 $raf->Read($buff, $length) == $length) or
1855 # or read from data (when processing Adobe DNGPrivateData)
1856 ($offset - $dataPos >= 0 and $offset - $dataPos + $length < $dataLen and
1857 ($buff = substr($$dataPt, $offset - $dataPos, $length))))
1858 {
1859 Decrypt(\$buff, 0, $length, $key);
1860 # display decrypted data in verbose mode
1861 if ($verbose > 2 and not $outfile) {
1862 $exifTool->VerboseDir("Decrypted SR2SubIFD", 0, $length);
1863 $exifTool->VerboseDump(\$buff, Addr => $offset + $base);
1864 }
1865 my $num = '';
1866 my $dPos = $offset;
1867 for (;;) {
1868 my %dirInfo = (
1869 Base => $base,
1870 DataPt => \$buff,
1871 DataLen => length $buff,
1872 DirStart => $offset - $dPos,
1873 DirName => "SR2SubIFD$num",
1874 DataPos => $dPos,
1875 );
1876 my $subTable = GetTagTable('Image::ExifTool::Sony::SR2SubIFD');
1877 if ($outfile) {
1878 my $fixup = new Image::ExifTool::Fixup;
1879 $dirInfo{Fixup} = $fixup;
1880 $result = $exifTool->WriteDirectory(\%dirInfo, $subTable);
1881 return undef unless $result;
1882 # save position of this SubIFD
1883 push @subifdPos, length($$outfile);
1884 # add this directory to the returned data
1885 $$fixup{Start} += length($$outfile);
1886 $$outfile .= $result;
1887 $dirInfo->{Fixup}->AddFixup($fixup);
1888 } else {
1889 $result = $exifTool->ProcessDirectory(\%dirInfo, $subTable);
1890 }
1891 last unless @offsets;
1892 $offset = shift @offsets;
1893 $num = ($num || 1) + 1;
1894 }
1895
1896 } else {
1897 $exifTool->Warn('Error reading SR2 data');
1898 }
1899 }
1900 if ($outfile and @subifdPos) {
1901 # the SR2SubIFD must be padded to a multiple of 4 bytes for the encryption
1902 my $sr2Len = length($$outfile) - $subifdPos[0];
1903 if ($sr2Len & 0x03) {
1904 my $pad = 4 - ($sr2Len & 0x03);
1905 $sr2Len += $pad;
1906 $$outfile .= ' ' x $pad;
1907 }
1908 # save the new SR2SubIFD Length and Key to be used later for encryption
1909 $$exifTool{SR2SubIFDLength} = $sr2Len;
1910 my $newKey = $$exifTool{VALUE}{SR2SubIFDKey};
1911 $$exifTool{SR2SubIFDKey} = $newKey if defined $newKey;
1912 # update SubIFD pointers manually and add to fixup, and set SR2SubIFDLength
1913 my $n = Get16u($outfile, 0);
1914 my ($i, %found);
1915 for ($i=0; $i<$n; ++$i) {
1916 my $entry = 2 + 12 * $i;
1917 my $tagID = Get16u($outfile, $entry);
1918 # only interested in SR2SubIFDOffset (0x7200) and SR2SubIFDLength (0x7201)
1919 next unless $tagID == 0x7200 or $tagID == 0x7201;
1920 $found{$tagID} = 1;
1921 my $fmt = Get16u($outfile, $entry + 2);
1922 if ($fmt != 0x04) { # must be int32u
1923 $exifTool->Error("Unexpected format ($fmt) for SR2SubIFD tag");
1924 return undef;
1925 }
1926 if ($tagID == 0x7201) { # SR2SubIFDLength
1927 Set32u($sr2Len, $outfile, $entry + 8);
1928 next;
1929 }
1930 my $tag = 'SR2SubIFDOffset';
1931 my $valuePtr = @subifdPos < 2 ? $entry+8 : Get32u($outfile, $entry+8);
1932 my $pos;
1933 foreach $pos (@subifdPos) {
1934 Set32u($pos, $outfile, $valuePtr);
1935 $dirInfo->{Fixup}->AddFixup($valuePtr, $tag);
1936 undef $tag;
1937 $valuePtr += 4;
1938 }
1939 }
1940 unless ($found{0x7200} and $found{0x7201}) {
1941 $exifTool->Error('Missing SR2SubIFD tag');
1942 return undef;
1943 }
1944 }
1945 return $outfile ? $$outfile : $result;
1946}
1947
19481; # end
1949
1950__END__
1951
1952=head1 NAME
1953
1954Image::ExifTool::Sony - Sony EXIF maker notes tags
1955
1956=head1 SYNOPSIS
1957
1958This module is loaded automatically by Image::ExifTool when required.
1959
1960=head1 DESCRIPTION
1961
1962This module contains definitions required by Image::ExifTool to interpret
1963Sony maker notes EXIF meta information.
1964
1965=head1 NOTES
1966
1967Also see Minolta.pm since Sony DSLR models use structures originating from
1968Minolta.
1969
1970=head1 AUTHOR
1971
1972Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
1973
1974This library is free software; you can redistribute it and/or modify it
1975under the same terms as Perl itself.
1976
1977=head1 REFERENCES
1978
1979=over 4
1980
1981=item L<http://www.cybercom.net/~dcoffin/dcraw/>
1982
1983=item L<http://homepage3.nifty.com/kamisaka/makernote/makernote_sony.htm>
1984
1985=item L<http://www.klingebiel.com/tempest/hd/pmp.html>
1986
1987=back
1988
1989=head1 ACKNOWLEDGEMENTS
1990
1991Thanks to Thomas Bodenmann, Philippe Devaux, Jens Duttke, Marcus
1992Holland-Moritz, Andrey Tverdokhleb, Rudiger Lange, Igal Milchtaich and
1993Michael Reitinger for help decoding some tags.
1994
1995=head1 SEE ALSO
1996
1997L<Image::ExifTool::TagNames/Sony Tags>,
1998L<Image::ExifTool::TagNames/Minolta Tags>,
1999L<Image::ExifTool(3pm)|Image::ExifTool>
2000
2001=cut
Note: See TracBrowser for help on using the repository browser.