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
|
---|
10 | # 3) Thomas Bodenmann private communication
|
---|
11 | #------------------------------------------------------------------------------
|
---|
12 |
|
---|
13 | package Image::ExifTool::Sony;
|
---|
14 |
|
---|
15 | use strict;
|
---|
16 | use vars qw($VERSION);
|
---|
17 | use Image::ExifTool qw(:DataAccess :Utils);
|
---|
18 | use Image::ExifTool::Exif;
|
---|
19 | use Image::ExifTool::Minolta;
|
---|
20 |
|
---|
21 | $VERSION = '1.10';
|
---|
22 |
|
---|
23 | sub ProcessSRF($$$);
|
---|
24 | sub ProcessSR2($$$);
|
---|
25 |
|
---|
26 | my %sonyLensIDs; # filled in based on Minolta LensID's
|
---|
27 |
|
---|
28 | %Image::ExifTool::Sony::Main = (
|
---|
29 | WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
|
---|
30 | CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
|
---|
31 | GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
|
---|
32 | 0x0e00 => {
|
---|
33 | Name => 'PrintIM',
|
---|
34 | Description => 'Print Image Matching',
|
---|
35 | SubDirectory => {
|
---|
36 | TagTable => 'Image::ExifTool::PrintIM::Main',
|
---|
37 | },
|
---|
38 | },
|
---|
39 | # 0xb020 string with observed values "Standard", "None" and "Real"
|
---|
40 | 0xb021 => { #2
|
---|
41 | Name => 'ColorTemperature',
|
---|
42 | PrintConv => '$val ? $val : "Auto"',
|
---|
43 | },
|
---|
44 | 0xb023 => { #PH (A100)
|
---|
45 | Name => 'SceneMode',
|
---|
46 | PrintConv => {
|
---|
47 | 0 => 'Manual (P,A,S or M)',
|
---|
48 | 1 => 'Portrait',
|
---|
49 | 4 => 'Sunset',
|
---|
50 | 5 => 'Sports',
|
---|
51 | 6 => 'Landscape',
|
---|
52 | 8 => 'Macro',
|
---|
53 | 16 => 'Auto',
|
---|
54 | 17 => 'Night Portrait',
|
---|
55 | },
|
---|
56 | },
|
---|
57 | 0xb024 => { #PH (A100)
|
---|
58 | Name => 'ZoneMatching',
|
---|
59 | PrintConv => {
|
---|
60 | 0 => 'ISO Setting Used',
|
---|
61 | 1 => 'High Key',
|
---|
62 | 2 => 'Low Key',
|
---|
63 | },
|
---|
64 | },
|
---|
65 | 0xb025 => { #PH (A100)
|
---|
66 | Name => 'DynamicRangeOptimizer',
|
---|
67 | PrintConv => {
|
---|
68 | 0 => 'Off',
|
---|
69 | 1 => 'Standard',
|
---|
70 | 2 => 'Advanced',
|
---|
71 | },
|
---|
72 | },
|
---|
73 | 0xb026 => { #PH (A100)
|
---|
74 | Name => 'ImageStabilization',
|
---|
75 | PrintConv => { 0 => 'Off', 1 => 'On' },
|
---|
76 | },
|
---|
77 | 0xb027 => { #2
|
---|
78 | Name => 'LensID',
|
---|
79 | PrintConv => \%sonyLensIDs,
|
---|
80 | },
|
---|
81 | 0xb028 => { #2
|
---|
82 | # (used by the DSLR-A100)
|
---|
83 | Name => 'MinoltaMakerNote',
|
---|
84 | Flags => 'SubIFD',
|
---|
85 | SubDirectory => {
|
---|
86 | TagTable => 'Image::ExifTool::Minolta::Main',
|
---|
87 | Start => '$val',
|
---|
88 | },
|
---|
89 | },
|
---|
90 | 0xb029 => { #2
|
---|
91 | Name => 'ColorMode',
|
---|
92 | Writable => 'int32u',
|
---|
93 | PrintConv => {
|
---|
94 | 0 => 'Standard',
|
---|
95 | 1 => 'Vivid',
|
---|
96 | 2 => 'Portrait',
|
---|
97 | 3 => 'Landscape',
|
---|
98 | 4 => 'Sunset',
|
---|
99 | 5 => 'Night Scene',
|
---|
100 | 6 => 'B&W',
|
---|
101 | 7 => 'Adobe RGB',
|
---|
102 | },
|
---|
103 | },
|
---|
104 | 0xb040 => { #2
|
---|
105 | Name => 'Macro',
|
---|
106 | PrintConv => { 0 => 'Off', 1 => 'On' },
|
---|
107 | },
|
---|
108 | 0xb041 => { #2
|
---|
109 | Name => 'ExposureMode',
|
---|
110 | PrintConv => {
|
---|
111 | 0 => 'Auto',
|
---|
112 | 5 => 'Landscape',
|
---|
113 | 6 => 'Program',
|
---|
114 | 7 => 'Aperture Priority',
|
---|
115 | 8 => 'Shutter Priority',
|
---|
116 | 9 => 'Night Scene',
|
---|
117 | 15 => 'Manual',
|
---|
118 | },
|
---|
119 | },
|
---|
120 | 0xb047 => { #2
|
---|
121 | Name => 'Quality',
|
---|
122 | PrintConv => {
|
---|
123 | 0 => 'Normal',
|
---|
124 | 1 => 'Fine',
|
---|
125 | },
|
---|
126 | },
|
---|
127 | 0xb04e => { #2
|
---|
128 | Name => 'LongExposureNoiseReduction',
|
---|
129 | PrintConv => { 0 => 'Off', 1 => 'On' },
|
---|
130 | },
|
---|
131 | );
|
---|
132 |
|
---|
133 | # tag table for Sony RAW Format
|
---|
134 | %Image::ExifTool::Sony::SRF = (
|
---|
135 | PROCESS_PROC => \&ProcessSRF,
|
---|
136 | GROUPS => { 0 => 'MakerNotes', 1 => 'SRF#', 2 => 'Camera' },
|
---|
137 | NOTES => q{
|
---|
138 | The maker notes in SRF (Sony Raw Format) images contain 7 IFD's (with family
|
---|
139 | 1 group names SRF0 through SRF6). SRF0 through SRF5 use these Sony tags,
|
---|
140 | while SRF6 uses standard EXIF tags. All information other than SRF0 is
|
---|
141 | encrypted, but thanks to Dave Coffin the decryption algorithm is known.
|
---|
142 | },
|
---|
143 | 0 => {
|
---|
144 | Name => 'SRF2_Key',
|
---|
145 | Notes => 'key to decrypt maker notes from the start of SRF2',
|
---|
146 | RawConv => '$self->{SRF2_Key} = $val',
|
---|
147 | },
|
---|
148 | 1 => {
|
---|
149 | Name => 'DataKey',
|
---|
150 | Notes => 'key to decrypt the rest of the file from the end of the maker notes',
|
---|
151 | RawConv => '$self->{SRFDataKey} = $val',
|
---|
152 | },
|
---|
153 | );
|
---|
154 |
|
---|
155 | # tag table for Sony RAW 2 Format Private IFD (ref 1)
|
---|
156 | %Image::ExifTool::Sony::SR2Private = (
|
---|
157 | PROCESS_PROC => \&ProcessSR2,
|
---|
158 | GROUPS => { 0 => 'MakerNotes', 1 => 'SR2', 2 => 'Camera' },
|
---|
159 | NOTES => q{
|
---|
160 | The SR2 format uses the DNGPrivateData tag to reference a private IFD
|
---|
161 | containing these tags.
|
---|
162 | },
|
---|
163 | 0x7200 => {
|
---|
164 | Name => 'SR2SubIFDOffset',
|
---|
165 | # (adjusting offset messes up calculations for AdobeSR2 in DNG images)
|
---|
166 | # Flags => 'IsOffset',
|
---|
167 | OffsetPair => 0x7201,
|
---|
168 | RawConv => '$self->{SR2SubIFDOffset} = $val',
|
---|
169 | },
|
---|
170 | 0x7201 => {
|
---|
171 | Name => 'SR2SubIFDLength',
|
---|
172 | OffsetPair => 0x7200,
|
---|
173 | RawConv => '$self->{SR2SubIFDLength} = $val',
|
---|
174 | },
|
---|
175 | 0x7221 => {
|
---|
176 | Name => 'SR2SubIFDKey',
|
---|
177 | Format => 'int32u',
|
---|
178 | Notes => 'key to decrypt SR2SubIFD',
|
---|
179 | RawConv => '$self->{SR2SubIFDKey} = $val',
|
---|
180 | },
|
---|
181 | );
|
---|
182 |
|
---|
183 | %Image::ExifTool::Sony::SR2SubIFD = (
|
---|
184 | GROUPS => { 0 => 'MakerNotes', 1 => 'SR2', 2 => 'Camera' },
|
---|
185 | NOTES => 'Tags in the encrypted SR2SubIFD',
|
---|
186 | 0x7303 => 'WB_GRBGLevels', #1
|
---|
187 | 0x74c0 => { #PH
|
---|
188 | Name => 'SR2DataIFD',
|
---|
189 | Flags => 'SubIFD',
|
---|
190 | SubDirectory => {
|
---|
191 | TagTable => 'Image::ExifTool::Sony::SR2DataIFD',
|
---|
192 | Start => '$val',
|
---|
193 | MaxSubdirs => 6,
|
---|
194 | },
|
---|
195 | },
|
---|
196 | 0x74a0 => 'MaxApertureAtMaxFocal', #PH
|
---|
197 | 0x74a1 => 'MaxApertureAtMinFocal', #PH
|
---|
198 | );
|
---|
199 |
|
---|
200 | %Image::ExifTool::Sony::SR2DataIFD = (
|
---|
201 | GROUPS => { 0 => 'MakerNotes', 1 => 'SR2', 2 => 'Camera' },
|
---|
202 | 0x7770 => 'ColorMode', #PH
|
---|
203 | );
|
---|
204 |
|
---|
205 | # fill in Sony LensID lookup based on Minolta values
|
---|
206 | {
|
---|
207 | my $id;
|
---|
208 | foreach $id (keys %Image::ExifTool::Minolta::minoltaLensIDs) {
|
---|
209 | # higher numbered lenses are missing last digit of ID
|
---|
210 | my $sonyID = ($id < 10000) ? $id : int($id / 10);
|
---|
211 | $sonyLensIDs{$sonyID} = $Image::ExifTool::Minolta::minoltaLensIDs{$id};
|
---|
212 | }
|
---|
213 | }
|
---|
214 |
|
---|
215 | #------------------------------------------------------------------------------
|
---|
216 | # decrypt Sony data (ref 1)
|
---|
217 | # Inputs: 0) data reference, 1) start offset, 2) data length, 3) decryption key
|
---|
218 | # Returns: nothing (original data buffer is updated with decrypted data)
|
---|
219 | sub Decrypt($$$$)
|
---|
220 | {
|
---|
221 | my ($dataPt, $start, $len, $key) = @_;
|
---|
222 | my ($i, $j, @pad);
|
---|
223 | my $words = $len / 4;
|
---|
224 |
|
---|
225 | for ($i=0; $i<4; ++$i) {
|
---|
226 | my $lo = ($key & 0xffff) * 0x0edd + 1;
|
---|
227 | my $hi = ($key >> 16) * 0x0edd + ($key & 0xffff) * 0x02e9 + ($lo >> 16);
|
---|
228 | $pad[$i] = $key = (($hi & 0xffff) << 16) + ($lo & 0xffff);
|
---|
229 | }
|
---|
230 | $pad[3] = ($pad[3] << 1 | ($pad[0]^$pad[2]) >> 31) & 0xffffffff;
|
---|
231 | for ($i=4; $i<0x7f; ++$i) {
|
---|
232 | $pad[$i] = (($pad[$i-4]^$pad[$i-2]) << 1 |
|
---|
233 | ($pad[$i-3]^$pad[$i-1]) >> 31) & 0xffffffff;
|
---|
234 | }
|
---|
235 | my @data = unpack("x$start N$words", $$dataPt);
|
---|
236 | for ($i=0x7f,$j=0; $j<$words; ++$i,++$j) {
|
---|
237 | $data[$j] ^= $pad[$i & 0x7f] = $pad[($i+1) & 0x7f] ^ $pad[($i+65) & 0x7f];
|
---|
238 | }
|
---|
239 | substr($$dataPt, $start, $words*4) = pack('N*', @data);
|
---|
240 | }
|
---|
241 |
|
---|
242 | #------------------------------------------------------------------------------
|
---|
243 | # Process SRF maker notes
|
---|
244 | # Inputs: 0) ExifTool object reference, 1) reference to directory information
|
---|
245 | # 2) pointer to tag table
|
---|
246 | # Returns: 1 on success
|
---|
247 | sub ProcessSRF($$$)
|
---|
248 | {
|
---|
249 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
250 | my $dataPt = $$dirInfo{DataPt};
|
---|
251 | my $dirLen = $$dirInfo{DirLen};
|
---|
252 | my $start = $$dirInfo{DirStart};
|
---|
253 | my $verbose = $exifTool->Options('Verbose');
|
---|
254 |
|
---|
255 | # process IFD chain
|
---|
256 | my ($ifd, $success);
|
---|
257 | for ($ifd=0; ; ) {
|
---|
258 | my $srf = $$dirInfo{DirName} = "SRF$ifd";
|
---|
259 | my $srfTable = $tagTablePtr;
|
---|
260 | # SRF6 uses standard EXIF tags
|
---|
261 | $srfTable = GetTagTable('Image::ExifTool::Exif::Main') if $ifd == 6;
|
---|
262 | $exifTool->{SET_GROUP1} = $srf;
|
---|
263 | $success = Image::ExifTool::Exif::ProcessExif($exifTool, $dirInfo, $srfTable);
|
---|
264 | delete $exifTool->{SET_GROUP1};
|
---|
265 | last unless $success;
|
---|
266 | #
|
---|
267 | # get pointer to next IFD
|
---|
268 | #
|
---|
269 | my $count = Get16u($dataPt, $$dirInfo{DirStart});
|
---|
270 | my $dirEnd = $$dirInfo{DirStart} + 2 + $count * 12;
|
---|
271 | last if $dirEnd + 4 > length($$dataPt);
|
---|
272 | my $nextIFD = Get32u($dataPt, $dirEnd);
|
---|
273 | last unless $nextIFD;
|
---|
274 | $nextIFD -= $$dirInfo{DataPos}; # adjust for position of makernotes data
|
---|
275 | $$dirInfo{DirStart} = $nextIFD;
|
---|
276 | #
|
---|
277 | # decrypt next IFD data if necessary
|
---|
278 | #
|
---|
279 | ++$ifd;
|
---|
280 | my ($key, $len);
|
---|
281 | if ($ifd == 1) {
|
---|
282 | # get the key to decrypt IFD1
|
---|
283 | my $cp = $start + 0x8ddc; # why?
|
---|
284 | my $ip = $cp + 4 * unpack("x$cp C", $$dataPt);
|
---|
285 | $key = unpack("x$ip N", $$dataPt);
|
---|
286 | $len = $cp + $nextIFD; # decrypt up to $cp
|
---|
287 | } elsif ($ifd == 2) {
|
---|
288 | # get the key to decrypt IFD2
|
---|
289 | $key = $exifTool->{SRF2_Key};
|
---|
290 | $len = length($$dataPt) - $nextIFD; # decrypt rest of maker notes
|
---|
291 | } else {
|
---|
292 | next; # no decryption needed
|
---|
293 | }
|
---|
294 | # decrypt data
|
---|
295 | Decrypt($dataPt, $nextIFD, $len, $key) if defined $key;
|
---|
296 | next unless $verbose > 2;
|
---|
297 | # display decrypted data in verbose mode
|
---|
298 | $exifTool->VerboseDir("Decrypted SRF$ifd", 0, $nextIFD + $len);
|
---|
299 | my %parms = (
|
---|
300 | Prefix => "$exifTool->{INDENT} ",
|
---|
301 | Start => $nextIFD,
|
---|
302 | DataPos => $$dirInfo{DataPos},
|
---|
303 | Out => $exifTool->Options('TextOut'),
|
---|
304 | );
|
---|
305 | $parms{MaxLen} = 96 unless $verbose > 3;
|
---|
306 | Image::ExifTool::HexDump($dataPt, $len, %parms);
|
---|
307 | }
|
---|
308 | }
|
---|
309 |
|
---|
310 | #------------------------------------------------------------------------------
|
---|
311 | # Process SR2 data
|
---|
312 | # Inputs: 0) ExifTool object reference, 1) reference to directory information
|
---|
313 | # 2) pointer to tag table
|
---|
314 | # Returns: 1 on success
|
---|
315 | sub ProcessSR2($$$)
|
---|
316 | {
|
---|
317 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
318 | my $dataPt = $$dirInfo{DataPt};
|
---|
319 | my $dataPos = $$dirInfo{DataPos};
|
---|
320 | my $dataLen = $$dirInfo{DataLen} || length $$dataPt;
|
---|
321 | my $dirLen = $$dirInfo{DirLen};
|
---|
322 | my $verbose = $exifTool->Options('Verbose');
|
---|
323 | my $result = Image::ExifTool::Exif::ProcessExif($exifTool, $dirInfo, $tagTablePtr);
|
---|
324 | return $result unless $result;
|
---|
325 | my $offset = $exifTool->{SR2SubIFDOffset};
|
---|
326 | my $length = $exifTool->{SR2SubIFDLength};
|
---|
327 | my $key = $exifTool->{SR2SubIFDKey};
|
---|
328 | my $raf = $$dirInfo{RAF};
|
---|
329 | my $base = $$dirInfo{Base} || 0;
|
---|
330 | if ($offset and $length and defined $key) {
|
---|
331 | my $buff;
|
---|
332 | # read encrypted SR2SubIFD from file
|
---|
333 | if (($raf and $raf->Seek($offset+$base, 0) and
|
---|
334 | $raf->Read($buff, $length) == $length) or
|
---|
335 | # or read from data (when processing Adobe DNGPrivateData)
|
---|
336 | ($offset - $dataPos >= 0 and $offset - $dataPos + $length < $dataLen and
|
---|
337 | ($buff = substr($$dataPt, $offset - $dataPos, $length))))
|
---|
338 | {
|
---|
339 | Decrypt(\$buff, 0, $length, $key);
|
---|
340 | # display decrypted data in verbose mode
|
---|
341 | if ($verbose > 2) {
|
---|
342 | $exifTool->VerboseDir("Decrypted SR2SubIFD", 0, $length);
|
---|
343 | my %parms = (
|
---|
344 | Out => $exifTool->{OPTIONS}->{TextOut},
|
---|
345 | Prefix => $exifTool->{INDENT},
|
---|
346 | Addr => $offset + $base,
|
---|
347 | );
|
---|
348 | $parms{MaxLen} = 96 unless $verbose > 3;
|
---|
349 | Image::ExifTool::HexDump(\$buff, $length, %parms);
|
---|
350 | }
|
---|
351 | my %dirInfo = (
|
---|
352 | Base => $base,
|
---|
353 | DataPt => \$buff,
|
---|
354 | DataLen => length $buff,
|
---|
355 | DirStart => 0,
|
---|
356 | DirName => 'SR2SubIFD',
|
---|
357 | DataPos => $offset,
|
---|
358 | );
|
---|
359 | my $subTable = Image::ExifTool::GetTagTable('Image::ExifTool::Sony::SR2SubIFD');
|
---|
360 | $result = $exifTool->ProcessDirectory(\%dirInfo, $subTable);
|
---|
361 |
|
---|
362 | } else {
|
---|
363 | $exifTool->Warn('Error reading SR2 data');
|
---|
364 | }
|
---|
365 | }
|
---|
366 | delete $exifTool->{SR2SubIFDOffset};
|
---|
367 | delete $exifTool->{SR2SubIFDLength};
|
---|
368 | delete $exifTool->{SR2SubIFDKey};
|
---|
369 | return $result;
|
---|
370 | }
|
---|
371 |
|
---|
372 | 1; # end
|
---|
373 |
|
---|
374 | __END__
|
---|
375 |
|
---|
376 | =head1 NAME
|
---|
377 |
|
---|
378 | Image::ExifTool::Sony - Sony EXIF maker notes tags
|
---|
379 |
|
---|
380 | =head1 SYNOPSIS
|
---|
381 |
|
---|
382 | This module is loaded automatically by Image::ExifTool when required.
|
---|
383 |
|
---|
384 | =head1 DESCRIPTION
|
---|
385 |
|
---|
386 | This module contains definitions required by Image::ExifTool to
|
---|
387 | interpret Sony maker notes EXIF meta information.
|
---|
388 |
|
---|
389 | =head1 NOTES
|
---|
390 |
|
---|
391 | The Sony maker notes use the standard EXIF IFD structure, but unfortunately
|
---|
392 | the entries are large blocks of binary data for which I can find no
|
---|
393 | documentation. You can use "exiftool -v3" to dump these blocks in hex.
|
---|
394 |
|
---|
395 | =head1 AUTHOR
|
---|
396 |
|
---|
397 | Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
|
---|
398 |
|
---|
399 | This library is free software; you can redistribute it and/or modify it
|
---|
400 | under the same terms as Perl itself.
|
---|
401 |
|
---|
402 | =head1 REFERENCES
|
---|
403 |
|
---|
404 | =over 4
|
---|
405 |
|
---|
406 | =item L<http://www.cybercom.net/~dcoffin/dcraw/>
|
---|
407 |
|
---|
408 | =item L<http://homepage3.nifty.com/kamisaka/makernote/makernote_sony.htm>
|
---|
409 |
|
---|
410 | =back
|
---|
411 |
|
---|
412 | =head1 ACKNOWLEDGEMENTS
|
---|
413 |
|
---|
414 | Thanks to Thomas Bodenmann for providing information about the LensID's.
|
---|
415 |
|
---|
416 | =head1 SEE ALSO
|
---|
417 |
|
---|
418 | L<Image::ExifTool::TagNames/Sony Tags>,
|
---|
419 | L<Image::ExifTool(3pm)|Image::ExifTool>
|
---|
420 |
|
---|
421 | =cut
|
---|