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

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

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

File size: 15.3 KB
Line 
1#------------------------------------------------------------------------------
2# File: SigmaRaw.pm
3#
4# Description: Read Sigma/Foveon RAW (X3F) meta information
5#
6# Revisions: 10/16/2005 - P. Harvey Created
7#
8# References: 1) http://www.x3f.info/technotes/FileDocs/X3F_Format.pdf
9#------------------------------------------------------------------------------
10
11package Image::ExifTool::SigmaRaw;
12
13use strict;
14use vars qw($VERSION);
15use Image::ExifTool qw(:DataAccess :Utils);
16
17$VERSION = '1.03';
18
19sub ProcessX3FHeader($$$);
20sub ProcessX3FDirectory($$$);
21sub ProcessX3FProperties($$$);
22
23# main X3F sections (plus header stuff)
24%Image::ExifTool::SigmaRaw::Main = (
25 PROCESS_PROC => \&ProcessX3FDirectory,
26 NOTES => 'These tags are used in Sigma and Foveon RAW (.X3F) images.',
27 Header => {
28 SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::Header' },
29 },
30 HeaderExt => {
31 SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::HeaderExt' },
32 },
33 PROP => {
34 Name => 'Properties',
35 SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::Properties' },
36 },
37 IMAG => {
38 Name => 'PreviewImage',
39 Binary => 1,
40 },
41 IMA2 => {
42 Name => 'PreviewImage',
43 Binary => 1,
44 },
45);
46
47# common X3F header structure
48%Image::ExifTool::SigmaRaw::Header = (
49 PROCESS_PROC => \&ProcessX3FHeader,
50 FORMAT => 'int32u',
51 1 => {
52 Name => 'FileVersion',
53 ValueConv => '($val >> 16) . "." . ($val & 0xffff)',
54 },
55 7 => 'ImageWidth',
56 8 => 'ImageHeight',
57 9 => 'Rotation',
58 10 => {
59 Name => 'WhiteBalance',
60 Format => 'string[32]',
61 },
62);
63
64# extended header tags
65%Image::ExifTool::SigmaRaw::HeaderExt = (
66 GROUPS => { 2 => 'Camera' },
67 NOTES => 'Extended header data found in version 2.1 and 2.2 files',
68 0 => 'Unused',
69 1 => { Name => 'ExposureAdjust',PrintConv => 'sprintf("%.2f",$val)' },
70 2 => { Name => 'Contrast', PrintConv => 'sprintf("%.2f",$val)' },
71 3 => { Name => 'Shadow', PrintConv => 'sprintf("%.2f",$val)' },
72 4 => { Name => 'Highlight', PrintConv => 'sprintf("%.2f",$val)' },
73 5 => { Name => 'Saturation', PrintConv => 'sprintf("%.2f",$val)' },
74 6 => { Name => 'Sharpness', PrintConv => 'sprintf("%.2f",$val)' },
75 7 => { Name => 'RedAdjust', PrintConv => 'sprintf("%.2f",$val)' },
76 8 => { Name => 'GreenAdjust', PrintConv => 'sprintf("%.2f",$val)' },
77 9 => { Name => 'BlueAdjust', PrintConv => 'sprintf("%.2f",$val)' },
78 10 => { Name => 'X3FillLight', PrintConv => 'sprintf("%.2f",$val)' },
79);
80
81# PROP tags
82%Image::ExifTool::SigmaRaw::Properties = (
83 PROCESS_PROC => \&ProcessX3FProperties,
84 GROUPS => { 2 => 'Camera' },
85 AEMODE => {
86 Name => 'MeteringMode',
87 PrintConv => {
88 8 => '8-segment',
89 C => 'Center-weighted average',
90 A => 'Average',
91 },
92 },
93 AFAREA => 'AFArea', # observed: CENTER_V
94 AFINFOCUS => 'AFInFocus', # observed: H
95 AFMODE => 'FocusMode',
96 AP_DESC => 'ApertureDisplayed',
97 APERTURE => {
98 Name => 'FNumber',
99 Groups => { 2 => 'Image' },
100 PrintConv => 'sprintf("%.1f",$val)',
101 },
102 BRACKET => 'BracketShot',
103 BURST => 'BurstShot',
104 CAMMANUF => 'Make',
105 CAMMODEL => 'Model',
106 CAMNAME => 'CameraName',
107 CAMSERIAL => 'SerialNumber',
108 COLORSPACE => 'ColorSpace', # observed: sRGB
109 DRIVE => {
110 Name => 'DriveMode',
111 PrintConv => {
112 SINGLE => 'Single Shot',
113 MULTI => 'Multi Shot',
114 '2S' => '2-sec Timer',
115 '10S' => '10-sec Timer',
116 UP => 'Mirror Up',
117 AB => 'Auto Bracket',
118 OFF => 'Off',
119 },
120 },
121 EVAL_STATE => 'EvalState', # observed: POST-EXPOSURE
122 EXPCOMP => {
123 Name => 'ExposureCompensation',
124 Groups => { 2 => 'Image' },
125 PrintConv => 'Image::ExifTool::Exif::ConvertFraction($val)',
126 },
127 EXPNET => {
128 Name => 'NetExposureCompensation',
129 Groups => { 2 => 'Image' },
130 PrintConv => 'Image::ExifTool::Exif::ConvertFraction($val)',
131 },
132 EXPTIME => {
133 Name => 'IntegrationTime',
134 Groups => { 2 => 'Image' },
135 ValueConv => '$val * 1e-6', # convert from usec
136 PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
137 },
138 FIRMVERS => 'FirmwareVersion',
139 FLASH => {
140 Name => 'FlashMode',
141 PrintConv => 'ucfirst(lc($val))',
142 },
143 FLASHEXPCOMP=> 'FlashExpComp',
144 FLASHPOWER => 'FlashPower',
145 FLASHTTLMODE=> 'FlashTTLMode', # observed: ON
146 FLASHTYPE => 'FlashType', # observed: NONE
147 FLENGTH => {
148 Name => 'FocalLength',
149 PrintConv => 'sprintf("%.1fmm",$val)',
150 },
151 FLEQ35MM => 'FocalLengthIn35mmFormat',
152 FOCUS => {
153 Name => 'Focus',
154 PrintConv => {
155 AF => 'Auto-focus Locked',
156 'NO LOCK' => "Auto-focus Didn't Lock",
157 M => 'Manual',
158 },
159 },
160 IMAGERBOARDID => 'ImagerBoardID',
161 IMAGERTEMP => 'SensorTemperature',
162 ISO => 'ISO',
163 LENSARANGE => 'LensApertureRange',
164 LENSFRANGE => 'LensFocalRange',
165 LENSMODEL => 'LensID',
166 PMODE => {
167 Name => 'ExposureProgram',
168 PrintConv => {
169 P => 'Program',
170 A => 'Aperture Priority',
171 S => 'Shutter Priority',
172 M => 'Manual',
173 },
174 },
175 RESOLUTION => {
176 Name => 'Quality',
177 PrintConv => {
178 LOW => 'Low',
179 MED => 'Medium',
180 HI => 'High',
181 },
182 },
183 SENSORID => 'SensorID',
184 SH_DESC => 'ShutterSpeedDisplayed',
185 SHUTTER => {
186 Name => 'ExposureTime',
187 Groups => { 2 => 'Image' },
188 PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
189 },
190 TIME => {
191 Name => 'DateTimeOriginal',
192 Groups => { 2 => 'Time' },
193 Description => 'Date/Time Original',
194 ValueConv => 'ConvertUnixTime($val)',
195 PrintConv => '$self->ConvertDateTime($val)',
196 },
197 WB_DESC => 'WhiteBalance',
198 VERSION_BF => 'VersionBF',
199);
200
201#------------------------------------------------------------------------------
202# Extract null-terminated unicode string from list of characters
203# Inputs: 0) ExifTool object ref, 1) list ref, 2) position in list
204# Returns: Converted string
205sub ExtractUnicodeString($$$)
206{
207 my ($exifTool, $chars, $pos) = @_;
208 my $i;
209 for ($i=$pos; $i<@$chars; ++$i) {
210 last unless $$chars[$i];
211 }
212 my $buff = pack('v*',@$chars[$pos..$i-1]);
213 my $val = $exifTool->Unicode2Charset($buff, 'II');
214 return $val;
215}
216
217#------------------------------------------------------------------------------
218# Process an X3F header
219# Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ref
220# Returns: 1 on success
221sub ProcessX3FHeader($$$)
222{
223 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
224 my $verbose = $exifTool->Options('Verbose');
225
226 # process the static header structure first
227 $exifTool->ProcessBinaryData($dirInfo, $tagTablePtr);
228
229 # process extended data if available
230 if ($$dirInfo{DirLen} >= 232) {
231 $verbose and $exifTool->VerboseDir('X3F HeaderExt', 32);
232 $tagTablePtr = GetTagTable('Image::ExifTool::SigmaRaw::HeaderExt');
233 my $dataPt = $$dirInfo{DataPt};
234 my @vals = unpack('x72C32V32', $$dataPt);
235 my $i;
236 my $unused = 0;
237 for ($i=0; $i<32; ++$i) {
238 $vals[$i] or ++$unused, next;
239 my $val = $vals[$i+32];
240 # convert value 0x40000000 => 2 ** 1, 0x3f800000 => 2 ** 0, 0x3f000000 => 2 ** -1
241 if ($val) {
242 my $sign;
243 if ($val & 0x80000000) {
244 $sign = -1;
245 $val &= 0x7fffffff;
246 } else {
247 $sign = 1;
248 }
249 $val = $sign * 2 ** (($val - 0x3f800000) / 0x800000);
250 }
251 $exifTool->HandleTag($tagTablePtr, $vals[$i], $val,
252 Index => $i,
253 DataPt => $dataPt,
254 Start => 104 + $i * 4,
255 Size => 4,
256 );
257 }
258 $exifTool->VPrint(0, "$exifTool->{INDENT}($unused entries unused)\n");
259 }
260 return 1;
261}
262
263#------------------------------------------------------------------------------
264# Process an X3F properties
265# Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ref
266# Returns: 1 on success
267sub ProcessX3FProperties($$$)
268{
269 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
270 my $dataPt = $$dirInfo{DataPt};
271 my $size = length($$dataPt);
272 my $verbose = $exifTool->Options('Verbose');
273 my $unknown = $exifTool->Options('Unknown');
274
275 unless ($size >= 24 and $$dataPt =~ /^SECp/) {
276 $exifTool->Warn('Bad properties header');
277 return 0;
278 }
279 my ($entries, $fmt, $len) = unpack('x8V2x4V', $$dataPt);
280 unless ($size >= 24 + 8 * $entries + $len) {
281 $exifTool->Warn('Truncated Property directory');
282 return 0;
283 }
284 $verbose and $exifTool->VerboseDir('Properties', $entries);
285 $fmt == 0 or $exifTool->Warn("Unsupported character format $fmt"), return 0;
286 my $charPos = 24 + 8 * $entries;
287 my @chars = unpack('v*',substr($$dataPt, $charPos, $len * 2));
288 my $index;
289 for ($index=0; $index<$entries; ++$index) {
290 my ($namePos, $valPos) = unpack('V2',substr($$dataPt, $index*8 + 24, 8));
291 if ($namePos >= @chars or $valPos >= @chars) {
292 $exifTool->Warn('Bad Property pointer');
293 return 0;
294 }
295 my $tag = ExtractUnicodeString($exifTool, \@chars, $namePos);
296 my $val = ExtractUnicodeString($exifTool, \@chars, $valPos);
297 if (not $$tagTablePtr{$tag} and $unknown and $tag =~ /^\w+$/) {
298 my $tagInfo = {
299 Name => "SigmaRaw_$tag",
300 Description => Image::ExifTool::MakeDescription('SigmaRaw', $tag),
301 Unknown => 1,
302 Writable => 0, # can't write unknown tags
303 };
304 # add tag information to table
305 Image::ExifTool::AddTagToTable($tagTablePtr, $tag, $tagInfo);
306 }
307
308 $exifTool->HandleTag($tagTablePtr, $tag, $val,
309 Index => $index,
310 DataPt => $dataPt,
311 Start => $charPos + 2 * $valPos,
312 Size => 2 * (length($val) + 1),
313 );
314 }
315 return 1;
316}
317
318#------------------------------------------------------------------------------
319# Process an X3F directory
320# Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ref
321# Returns: error string or undef on success
322sub ProcessX3FDirectory($$$)
323{
324 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
325 my $raf = $$dirInfo{RAF};
326 my $verbose = $exifTool->Options('Verbose');
327
328 $raf->Seek($$dirInfo{DirStart}, 0) or return 'Error seeking to directory start';
329
330 # parse the X3F directory structure
331 my ($buff, $ver, $entries, $index);
332 $raf->Read($buff, 12) == 12 or return 'Truncated X3F image';
333 $buff =~ /^SECd/ or return 'Bad section header';
334 ($ver, $entries) = unpack('x4V2', $buff);
335 $verbose and $exifTool->VerboseDir('X3F Subsection', $entries);
336 my $dir;
337 $raf->Read($dir, $entries * 12) == $entries * 12 or return 'Truncated X3F directory';
338 for ($index=0; $index<$entries; ++$index) {
339 my $pos = $index * 12;
340 my ($offset, $len, $tag) = unpack("x${pos}V2a4", $dir);
341 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
342 if ($verbose) {
343 $exifTool->VPrint(0, "$exifTool->{INDENT}$index) $tag Subsection ($len bytes):\n");
344 if ($verbose > 2) {
345 $raf->Seek($offset, 0) or return 'Error seeking';
346 my $n = $verbose > 3 ? $len : 64;
347 $n = $len if $n > $len;
348 $raf->Read($buff, $n) == $n or return 'Truncated image';
349 Image::ExifTool::HexDump(\$buff, undef,
350 Prefix => $exifTool->{INDENT},
351 Out => $exifTool->Options('TextOut'),
352 );
353 }
354 }
355 next unless $tagInfo;
356 $raf->Seek($offset, 0) or return "Error seeking for $$tagInfo{Name}";
357 if ($$tagInfo{Name} eq 'PreviewImage') {
358 # check image header to see if this is a JPEG preview image
359 $raf->Read($buff, 28) == 28 or return 'Error reading PreviewImage header';
360 # igore all image data but JPEG compressed (type 18)
361 next unless $buff =~ /^SECi.{4}\x02\0\0\0\x12/s;
362 $len -= 28;
363 }
364 $raf->Read($buff, $len) == $len or return "Error reading $$tagInfo{Name} data";
365 my $subdir = $$tagInfo{SubDirectory};
366 if ($subdir) {
367 my %dirInfo = ( DataPt => \$buff );
368 my $subTable = GetTagTable($$subdir{TagTable});
369 $exifTool->ProcessDirectory(\%dirInfo, $subTable);
370 } else {
371 $exifTool->FoundTag($tagInfo, $buff);
372 }
373 }
374 return undef;
375}
376
377#------------------------------------------------------------------------------
378# Extract information from a Sigma raw (X3F) image
379# Inputs: 0) ExifTool object reference, 1) DirInfo reference
380# Returns: 1 on success, 0 if this wasn't a valid X3F image
381sub ProcessX3F($$)
382{
383 my ($exifTool, $dirInfo) = @_;
384 my $raf = $$dirInfo{RAF};
385 my $buff;
386
387 return 0 unless $raf->Read($buff, 40) == 40;
388 return 0 unless $buff =~ /^FOVb/;
389
390 SetByteOrder('II');
391 $exifTool->SetFileType();
392
393 # check version number
394 my $ver = unpack('x4V',$buff);
395 $ver = ($ver >> 16) . '.' . ($ver & 0xffff);
396 if ($ver >= 3) {
397 $exifTool->Warn("Can't read version $ver X3F image");
398 return 1;
399 }
400 # read version 2.1/2.2 extended header
401 if ($ver > 2) {
402 my $buf2;
403 unless ($raf->Read($buf2, 192) == 192) {
404 $exifTool->Warn('Error reading extended header');
405 return 1;
406 }
407 $buff .= $buf2;
408 }
409 # process header information
410 my $tagTablePtr = GetTagTable('Image::ExifTool::SigmaRaw::Main');
411 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, 'Header');
412 my $subdir = GetTagTable('Image::ExifTool::SigmaRaw::Header');
413 my %dirInfo = (
414 DataPt => \$buff,
415 DirStart => 0,
416 DirLen => length($buff),
417 );
418 $exifTool->ProcessDirectory(\%dirInfo, $subdir);
419 # read the directory pointer
420 $raf->Seek(-4, 2);
421 unless ($raf->Read($buff, 4) == 4) {
422 $exifTool->Warn('Error reading X3F dir pointer');
423 return 1;
424 }
425 my $offset = unpack('V', $buff);
426 %dirInfo = (
427 RAF => $raf,
428 DirStart => $offset,
429 );
430 # process the X3F subsections
431 my $err = $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);
432 $err and $exifTool->Warn($err);
433 return 1;
434}
435
4361; # end
437
438__END__
439
440=head1 NAME
441
442Image::ExifTool::SigmaRaw - Read Sigma/Foveon RAW (X3F) meta information
443
444=head1 SYNOPSIS
445
446This module is loaded automatically by Image::ExifTool when required.
447
448=head1 DESCRIPTION
449
450This module contains definitions required by Image::ExifTool to read
451Sigma and Foveon X3F images.
452
453=head1 AUTHOR
454
455Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
456
457This library is free software; you can redistribute it and/or modify it
458under the same terms as Perl itself.
459
460=head1 REFERENCES
461
462=over 4
463
464=item L<http://www.x3f.info/technotes/FileDocs/X3F_Format.pdf>
465
466=back
467
468=head1 SEE ALSO
469
470L<Image::ExifTool::TagNames/SigmaRaw Tags>,
471L<Image::ExifTool::Sigma(3pm)|Image::ExifTool::Sigma>,
472L<Image::ExifTool(3pm)|Image::ExifTool>
473
474=cut
Note: See TracBrowser for help on using the repository browser.