source: gs2-extensions/parallel-building/trunk/src/perllib/cpan/Image/ExifTool/SigmaRaw.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: 23.8 KB
RevLine 
[24626]1#------------------------------------------------------------------------------
2# File: SigmaRaw.pm
3#
4# Description: Read Sigma/Foveon RAW (X3F) meta information
5#
6# Revisions: 2005/10/16 - P. Harvey Created
7# 2009/11/30 - P. Harvey Support X3F v2.3 written by Sigma DP2
8#
9# References: 1) http://www.x3f.info/technotes/FileDocs/X3F_Format.pdf
10#------------------------------------------------------------------------------
11
12package Image::ExifTool::SigmaRaw;
13
14use strict;
15use vars qw($VERSION);
16use Image::ExifTool qw(:DataAccess :Utils);
17
18$VERSION = '1.14';
19
20sub ProcessX3FHeader($$$);
21sub ProcessX3FDirectory($$$);
22sub ProcessX3FProperties($$$);
23
24# sigma LensType lookup (ref PH)
25my %sigmaLensTypes = (
26 # 0 => 'Sigma 50mm F2.8 EX Macro', (0 used for other lenses too)
27 # 8 - 18-125mm LENSARANGE@18mm=22-4
28 16 => 'Sigma 18-50mm F3.5-5.6 DC',
29 129 => 'Sigma 14mm F2.8 EX Aspherical',
30 131 => 'Sigma 17-70mm F2.8-4.5 DC Macro',
31 145 => 'Sigma Lens (145)',
32 145.1 => 'Sigma 15-30mm F3.5-4.5 EX DG Aspherical',
33 145.2 => 'Sigma 18-50mm F2.8 EX DG', #(NC)
34 145.3 => 'Sigma 20-40mm F2.8 EX DG',
35 165 => 'Sigma 70-200mm F2.8 EX', # ...but what specific model?:
36 # 70-200mm F2.8 EX APO - Original version, minimum focus distance 1.8m (1999)
37 # 70-200mm F2.8 EX DG - Adds 'digitally optimized' lens coatings to reduce flare (2005)
38 # 70-200mm F2.8 EX DG Macro (HSM) - Minimum focus distance reduced to 1m (2006)
39 # 70-200mm F2.8 EX DG Macro HSM II - Improved optical performance (2007)
40 169 => 'Sigma 18-50mm F2.8 EX DC', #(NC)
41 '100' => 'Sigma 24-70mm f/2.8 DG Macro', # (SD15)
42 8900 => 'Sigma 70-300mm f/4-5.6 DG OS', # (SD15)
43);
44
45# main X3F sections (plus header stuff)
46%Image::ExifTool::SigmaRaw::Main = (
47 PROCESS_PROC => \&ProcessX3FDirectory,
48 NOTES => q{
49 These tags are used in Sigma and Foveon RAW (.X3F) images. Metadata is also
50 extracted from the JpgFromRaw image if it exists (all models but the SD9 and
51 SD10). Currently, metadata may only be written to the embedded JpgFromRaw.
52 },
53 Header => {
54 SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::Header' },
55 },
56 HeaderExt => {
57 SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::HeaderExt' },
58 },
59 PROP => {
60 Name => 'Properties',
61 SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::Properties' },
62 },
63 IMAG => {
64 Name => 'PreviewImage',
65 Binary => 1,
66 },
67 IMA2 => [
68 {
69 Name => 'PreviewImage',
70 Condition => 'not $$self{IsJpgFromRaw}',
71 Binary => 1,
72 },
73 {
74 Name => 'JpgFromRaw',
75 Binary => 1,
76 },
77 ]
78);
79
80# common X3F header structure
81%Image::ExifTool::SigmaRaw::Header = (
82 PROCESS_PROC => \&ProcessX3FHeader,
83 FORMAT => 'int32u',
84 1 => {
85 Name => 'FileVersion',
86 ValueConv => '($val >> 16) . "." . ($val & 0xffff)',
87 },
88 2 => {
89 Name => 'ImageUniqueID',
90 # the serial number (with an extra leading "0") makes up
91 # the first 8 digits of this UID,
92 Format => 'undef[16]',
93 ValueConv => 'unpack("H*", $val)',
94 },
95 6 => {
96 Name => 'MarkBits',
97 PrintConv => { BITMASK => { } },
98 },
99 7 => 'ImageWidth',
100 8 => 'ImageHeight',
101 9 => 'Rotation',
102 10 => {
103 Name => 'WhiteBalance',
104 Format => 'string[32]',
105 },
106 18 => { #PH (DP2, FileVersion 2.3)
107 Name => 'SceneCaptureType',
108 Format => 'string[32]',
109 },
110);
111
112# extended header tags
113%Image::ExifTool::SigmaRaw::HeaderExt = (
114 GROUPS => { 2 => 'Camera' },
115 NOTES => 'Extended header data found in version 2.1 and 2.2 files',
116 0 => 'Unused',
117 1 => { Name => 'ExposureAdjust',PrintConv => 'sprintf("%.1f",$val)' },
118 2 => { Name => 'Contrast', PrintConv => 'sprintf("%.1f",$val)' },
119 3 => { Name => 'Shadow', PrintConv => 'sprintf("%.1f",$val)' },
120 4 => { Name => 'Highlight', PrintConv => 'sprintf("%.1f",$val)' },
121 5 => { Name => 'Saturation', PrintConv => 'sprintf("%.1f",$val)' },
122 6 => { Name => 'Sharpness', PrintConv => 'sprintf("%.1f",$val)' },
123 7 => { Name => 'RedAdjust', PrintConv => 'sprintf("%.1f",$val)' },
124 8 => { Name => 'GreenAdjust', PrintConv => 'sprintf("%.1f",$val)' },
125 9 => { Name => 'BlueAdjust', PrintConv => 'sprintf("%.1f",$val)' },
126 10 => { Name => 'X3FillLight', PrintConv => 'sprintf("%.1f",$val)' },
127);
128
129# PROP tags
130%Image::ExifTool::SigmaRaw::Properties = (
131 PROCESS_PROC => \&ProcessX3FProperties,
132 GROUPS => { 2 => 'Camera' },
133 AEMODE => {
134 Name => 'MeteringMode',
135 PrintConv => {
136 8 => '8-segment',
137 C => 'Center-weighted average',
138 A => 'Average',
139 },
140 },
141 AFAREA => 'AFArea', # observed: CENTER_V
142 AFINFOCUS => 'AFInFocus', # observed: H
143 AFMODE => 'FocusMode',
144 AP_DESC => 'ApertureDisplayed',
145 APERTURE => {
146 Name => 'FNumber',
147 Groups => { 2 => 'Image' },
148 PrintConv => 'sprintf("%.1f",$val)',
149 },
150 BRACKET => 'BracketShot',
151 BURST => 'BurstShot',
152 CAMMANUF => 'Make',
153 CAMMODEL => 'Model',
154 CAMNAME => 'CameraName',
155 CAMSERIAL => 'SerialNumber',
156 CM_DESC => 'SceneCaptureType', #PH (DP2)
157 COLORSPACE => 'ColorSpace', # observed: sRGB
158 DRIVE => {
159 Name => 'DriveMode',
160 PrintConv => {
161 SINGLE => 'Single Shot',
162 MULTI => 'Multi Shot',
163 '2S' => '2 s Timer',
164 '10S' => '10 s Timer',
165 UP => 'Mirror Up',
166 AB => 'Auto Bracket',
167 OFF => 'Off',
168 },
169 },
170 EVAL_STATE => 'EvalState', # observed: POST-EXPOSURE
171 EXPCOMP => {
172 Name => 'ExposureCompensation',
173 Groups => { 2 => 'Image' },
174 PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)',
175 },
176 EXPNET => {
177 Name => 'NetExposureCompensation',
178 Groups => { 2 => 'Image' },
179 PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)',
180 },
181 EXPTIME => {
182 Name => 'IntegrationTime',
183 Groups => { 2 => 'Image' },
184 ValueConv => '$val * 1e-6', # convert from usec
185 PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
186 },
187 FIRMVERS => 'FirmwareVersion',
188 FLASH => {
189 Name => 'FlashMode',
190 PrintConv => 'ucfirst(lc($val))',
191 },
192 FLASHEXPCOMP=> 'FlashExpComp',
193 FLASHPOWER => 'FlashPower',
194 FLASHTTLMODE=> 'FlashTTLMode', # observed: ON
195 FLASHTYPE => 'FlashType', # observed: NONE
196 FLENGTH => {
197 Name => 'FocalLength',
198 PrintConv => 'sprintf("%.1f mm",$val)',
199 },
200 FLEQ35MM => {
201 Name => 'FocalLengthIn35mmFormat',
202 PrintConv => 'sprintf("%.1f mm",$val)',
203 },
204 FOCUS => {
205 Name => 'Focus',
206 PrintConv => {
207 AF => 'Auto-focus Locked',
208 'NO LOCK' => "Auto-focus Didn't Lock",
209 M => 'Manual',
210 },
211 },
212 IMAGERBOARDID => 'ImagerBoardID',
213 IMAGERTEMP => {
214 Name => 'SensorTemperature',
215 PrintConv => '"$val C"',
216 },
217 IMAGEBOARDID=> 'ImageBoardID', #PH (DP2)
218 ISO => 'ISO',
219 LENSARANGE => 'LensApertureRange',
220 LENSFRANGE => 'LensFocalRange',
221 LENSMODEL => {
222 Name => 'LensType',
223 Notes => q{
224 decimal values differentiate lenses which would otherwise have the same
225 LensType, and are used by the Composite LensID tag when attempting to
226 identify the specific lens model
227 },
228 PrintConv => \%sigmaLensTypes,
229 },
230 PMODE => {
231 Name => 'ExposureProgram',
232 PrintConv => {
233 P => 'Program',
234 A => 'Aperture Priority',
235 S => 'Shutter Priority',
236 M => 'Manual',
237 },
238 },
239 RESOLUTION => {
240 Name => 'Quality',
241 PrintConv => {
242 LOW => 'Low',
243 MED => 'Medium',
244 HI => 'High',
245 },
246 },
247 SENSORID => 'SensorID',
248 SH_DESC => 'ShutterSpeedDisplayed',
249 SHUTTER => {
250 Name => 'ExposureTime',
251 Groups => { 2 => 'Image' },
252 PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
253 },
254 TIME => {
255 Name => 'DateTimeOriginal',
256 Groups => { 2 => 'Time' },
257 Description => 'Date/Time Original',
258 ValueConv => 'ConvertUnixTime($val)',
259 PrintConv => '$self->ConvertDateTime($val)',
260 },
261 WB_DESC => 'WhiteBalance',
262 VERSION_BF => 'VersionBF',
263);
264
265#------------------------------------------------------------------------------
266# Extract null-terminated unicode string from list of characters
267# Inputs: 0) ExifTool object ref, 1) list ref, 2) position in list
268# Returns: Converted string
269sub ExtractUnicodeString($$$)
270{
271 my ($exifTool, $chars, $pos) = @_;
272 my $i;
273 for ($i=$pos; $i<@$chars; ++$i) {
274 last unless $$chars[$i];
275 }
276 my $buff = pack('v*', @$chars[$pos..$i-1]);
277 return $exifTool->Decode($buff, 'UCS2', 'II');
278}
279
280#------------------------------------------------------------------------------
281# Process an X3F header
282# Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ref
283# Returns: 1 on success
284sub ProcessX3FHeader($$$)
285{
286 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
287 my $dataPt = $$dirInfo{DataPt};
288 my $hdrLen = $$dirInfo{DirLen};
289 my $verbose = $exifTool->Options('Verbose');
290
291 # process the static header structure first
292 $exifTool->ProcessBinaryData($dirInfo, $tagTablePtr);
293
294 # process extended data if available
295 if (length $$dataPt >= 232) {
296 if ($verbose) {
297 $exifTool->VerboseDir('X3F HeaderExt', 32);
298 Image::ExifTool::HexDump($dataPt, undef,
299 MaxLen => $verbose > 3 ? 1024 : 96,
300 Out => $exifTool->Options('TextOut'),
301 Prefix => $$exifTool{INDENT},
302 Start => $$dirInfo{DirLen},
303 ) if $verbose > 2;
304 }
305 $tagTablePtr = GetTagTable('Image::ExifTool::SigmaRaw::HeaderExt');
306 my @vals = unpack("x${hdrLen}C32V32", $$dataPt);
307 my $i;
308 my $unused = 0;
309 for ($i=0; $i<32; ++$i) {
310 $vals[$i] or ++$unused, next;
311 my $val = $vals[$i+32];
312 # convert value 0x40000000 => 2 ** 1, 0x3f800000 => 2 ** 0, 0x3f000000 => 2 ** -1
313 if ($val) {
314 my $sign;
315 if ($val & 0x80000000) {
316 $sign = -1;
317 $val &= 0x7fffffff;
318 } else {
319 $sign = 1;
320 }
321 $val = $sign * 2 ** (($val - 0x3f800000) / 0x800000);
322 }
323 $exifTool->HandleTag($tagTablePtr, $vals[$i], $val,
324 Index => $i,
325 DataPt => $dataPt,
326 Start => $hdrLen + 32 + $i * 4,
327 Size => 4,
328 );
329 }
330 $exifTool->VPrint(0, "$exifTool->{INDENT}($unused entries unused)\n");
331 }
332 return 1;
333}
334
335#------------------------------------------------------------------------------
336# Process an X3F properties
337# Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ref
338# Returns: 1 on success
339sub ProcessX3FProperties($$$)
340{
341 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
342 my $dataPt = $$dirInfo{DataPt};
343 my $size = length($$dataPt);
344 my $verbose = $exifTool->Options('Verbose');
345 my $unknown = $exifTool->Options('Unknown');
346
347 unless ($size >= 24 and $$dataPt =~ /^SECp/) {
348 $exifTool->Warn('Bad properties header');
349 return 0;
350 }
351 my ($entries, $fmt, $len) = unpack('x8V2x4V', $$dataPt);
352 unless ($size >= 24 + 8 * $entries + $len) {
353 $exifTool->Warn('Truncated Property directory');
354 return 0;
355 }
356 $verbose and $exifTool->VerboseDir('Properties', $entries);
357 $fmt == 0 or $exifTool->Warn("Unsupported character format $fmt"), return 0;
358 my $charPos = 24 + 8 * $entries;
359 my @chars = unpack('v*',substr($$dataPt, $charPos, $len * 2));
360 my $index;
361 for ($index=0; $index<$entries; ++$index) {
362 my ($namePos, $valPos) = unpack('V2',substr($$dataPt, $index*8 + 24, 8));
363 if ($namePos >= @chars or $valPos >= @chars) {
364 $exifTool->Warn('Bad Property pointer');
365 return 0;
366 }
367 my $tag = ExtractUnicodeString($exifTool, \@chars, $namePos);
368 my $val = ExtractUnicodeString($exifTool, \@chars, $valPos);
369 if (not $$tagTablePtr{$tag} and $unknown and $tag =~ /^\w+$/) {
370 my $tagInfo = {
371 Name => "SigmaRaw_$tag",
372 Description => Image::ExifTool::MakeDescription('SigmaRaw', $tag),
373 Unknown => 1,
374 Writable => 0, # can't write unknown tags
375 };
376 # add tag information to table
377 Image::ExifTool::AddTagToTable($tagTablePtr, $tag, $tagInfo);
378 }
379
380 $exifTool->HandleTag($tagTablePtr, $tag, $val,
381 Index => $index,
382 DataPt => $dataPt,
383 Start => $charPos + 2 * $valPos,
384 Size => 2 * (length($val) + 1),
385 );
386 }
387 return 1;
388}
389
390#------------------------------------------------------------------------------
391# Write an X3F file
392# Inputs: 0) ExifTool object reference, 1) DirInfo reference (DirStart = directory offset)
393# Returns: error string, undef on success, or -1 on write error
394# Notes: Writes metadata to embedded JpgFromRaw image
395sub WriteX3F($$)
396{
397 my ($exifTool, $dirInfo) = @_;
398 my $raf = $$dirInfo{RAF};
399 my $outfile = $$dirInfo{OutFile};
400 my ($outDir, $buff, $ver, $entries, $dir, $outPos, $index, $didContain);
401
402 $raf->Seek($$dirInfo{DirStart}, 0) or return 'Error seeking to directory start';
403
404 # read the X3F directory header (will be copied directly to output)
405 $raf->Read($outDir, 12) == 12 or return 'Truncated X3F image';
406 $outDir =~ /^SECd/ or return 'Bad section header';
407 ($ver, $entries) = unpack('x4V2', $outDir);
408
409 # do sanity check on number of entries in directory
410 return 'Invalid X3F directory count' unless $entries > 2 and $entries < 20;
411 # read the directory entries
412 unless ($raf->Read($dir, $entries * 12) == $entries * 12) {
413 return 'Truncated X3F directory';
414 }
415 # do a quick scan to determine the offset of the first data subsection
416 for ($index=0; $index<$entries; ++$index) {
417 my $pos = $index * 12;
418 my ($offset, $len, $tag) = unpack("x${pos}V2a4", $dir);
419 # remember position of first data subsection
420 $outPos = $offset if not defined $outPos or $outPos > $offset;
421 }
422 # copy the file header up to the start of the first data subsection
423 unless ($raf->Seek(0,0) and $raf->Read($buff, $outPos) == $outPos) {
424 return 'Error reading X3F header';
425 }
426 Write($outfile, $buff) or return -1;
427
428 # loop through directory, rewriting each section
429 for ($index=0; $index<$entries; ++$index) {
430
431 my $pos = $index * 12;
432 my ($offset, $len, $tag) = unpack("x${pos}V2a4", $dir);
433 $raf->Seek($offset, 0) or return 'Bad data offset';
434
435 if ($tag eq 'IMA2' and $len > 28) {
436 # check subsection header (28 bytes) to see if this is a JPEG preview image
437 $raf->Read($buff, 28) == 28 or return 'Error reading PreviewImage header';
438 Write($outfile, $buff) or return -1;
439 $len -= 28;
440
441 # only rewrite full-sized JpgFromRaw (version 2.0, type 2, format 18)
442 if ($buff =~ /^SECi\0\0\x02\0\x02\0\0\0\x12\0\0\0/ and
443 $$exifTool{ImageWidth} == unpack('x16V', $buff))
444 {
445 $raf->Read($buff, $len) == $len or return 'Error reading JpgFromRaw';
446 # use same write directories as JPEG
447 $exifTool->InitWriteDirs('JPEG');
448 # rewrite the embedded JPEG in memory
449 my $newData;
450 my %jpegInfo = (
451 Parent => 'X3F',
452 RAF => new File::RandomAccess(\$buff),
453 OutFile => \$newData,
454 );
455 $$exifTool{FILE_TYPE} = 'JPEG';
456 my $success = $exifTool->WriteJPEG(\%jpegInfo);
457 $$exifTool{FILE_TYPE} = 'X3F';
458 SetByteOrder('II');
459 return 'Error writing X3F JpgFromRaw' unless $success and $newData;
460 return -1 if $success < 0;
461 # write new data if anything changed, otherwise copy old image
462 my $outPt = $$exifTool{CHANGED} ? \$newData : \$buff;
463 Write($outfile, $$outPt) or return -1;
464 # set $len to the total subsection data length
465 $len = length($$outPt) + 28;
466 $didContain = 1;
467 } else {
468 # copy original image data
469 Image::ExifTool::CopyBlock($raf, $outfile, $len) or return 'Corrupted X3F image';
470 $len += 28;
471 }
472 } else {
473 # copy data for this subsection
474 Image::ExifTool::CopyBlock($raf, $outfile, $len) or return 'Corrupted X3F directory';
475 }
476 # add directory entry and update output file position
477 $outDir .= pack('V2a4', $outPos, $len, $tag);
478 $outPos += $len;
479 # pad data to an even 4-byte boundary
480 if ($len & 0x03) {
481 my $pad = 4 - ($len & 0x03);
482 Write($outfile, "\0" x $pad) or return -1;
483 $outPos += $pad;
484 }
485 }
486 # warn if we couldn't add metadata to this image (should only be SD9 or SD10)
487 $didContain or $exifTool->Warn("Can't yet write SD9 or SD10 X3F images");
488 # write out the directory and the directory pointer, and we are done
489 Write($outfile, $outDir, pack('V', $outPos)) or return -1;
490 return undef;
491}
492
493#------------------------------------------------------------------------------
494# Process an X3F directory
495# Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ref
496# Returns: error string or undef on success
497sub ProcessX3FDirectory($$$)
498{
499 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
500 my $raf = $$dirInfo{RAF};
501 my $verbose = $exifTool->Options('Verbose');
502
503 $raf->Seek($$dirInfo{DirStart}, 0) or return 'Error seeking to directory start';
504
505 # parse the X3F directory structure
506 my ($buff, $ver, $entries, $index, $dir);
507 $raf->Read($buff, 12) == 12 or return 'Truncated X3F image';
508 $buff =~ /^SECd/ or return 'Bad section header';
509 ($ver, $entries) = unpack('x4V2', $buff);
510 $verbose and $exifTool->VerboseDir('X3F Subsection', $entries);
511 $raf->Read($dir, $entries * 12) == $entries * 12 or return 'Truncated X3F directory';
512 for ($index=0; $index<$entries; ++$index) {
513 my $pos = $index * 12;
514 my ($offset, $len, $tag) = unpack("x${pos}V2a4", $dir);
515 my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
516 if ($verbose) {
517 $exifTool->VPrint(0, "$exifTool->{INDENT}$index) $tag Subsection ($len bytes):\n");
518 if ($verbose > 2) {
519 $raf->Seek($offset, 0) or return 'Error seeking';
520 $raf->Read($buff, $len) == $len or return 'Truncated image';
521 $exifTool->VerboseDump(\$buff);
522 }
523 }
524 next unless $tagInfo;
525 $raf->Seek($offset, 0) or return "Error seeking for $$tagInfo{Name}";
526 if ($$tagInfo{Name} eq 'PreviewImage') {
527 # check image header to see if this is a JPEG preview image
528 $raf->Read($buff, 28) == 28 or return 'Error reading PreviewImage header';
529 # ignore all image data but JPEG compressed (version 2.0, type 2, format 18)
530 next unless $buff =~ /^SECi\0\0\x02\0\x02\0\0\0\x12\0\0\0/;
531 # check preview image size and extract full-sized preview as JpgFromRaw
532 if ($$exifTool{ImageWidth} == unpack('x16V', $buff)) {
533 $$exifTool{IsJpgFromRaw} = 1;
534 $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
535 delete $$exifTool{IsJpgFromRaw};
536 }
537 $offset += 28;
538 $len -= 28;
539 }
540 $raf->Read($buff, $len) == $len or return "Error reading $$tagInfo{Name} data";
541 my $subdir = $$tagInfo{SubDirectory};
542 if ($subdir) {
543 my %dirInfo = ( DataPt => \$buff );
544 my $subTable = GetTagTable($$subdir{TagTable});
545 $exifTool->ProcessDirectory(\%dirInfo, $subTable);
546 } else {
547 # extract metadata from JpgFromRaw
548 if ($$tagInfo{Name} eq 'JpgFromRaw') {
549 my %dirInfo = (
550 Parent => 'X3F',
551 RAF => new File::RandomAccess(\$buff),
552 );
553 $$exifTool{BASE} += $offset;
554 $exifTool->ProcessJPEG(\%dirInfo);
555 $$exifTool{BASE} -= $offset;
556 SetByteOrder('II');
557 }
558 $exifTool->FoundTag($tagInfo, $buff);
559 }
560 }
561 return undef;
562}
563
564#------------------------------------------------------------------------------
565# Read/write information from a Sigma raw (X3F) image
566# Inputs: 0) ExifTool object reference, 1) DirInfo reference
567# Returns: 1 on success, 0 if this wasn't a valid X3F image, or -1 on write error
568sub ProcessX3F($$)
569{
570 my ($exifTool, $dirInfo) = @_;
571 my $outfile = $$dirInfo{OutFile};
572 my $raf = $$dirInfo{RAF};
573 my $warn = $outfile ? \&Image::ExifTool::Error : \&Image::ExifTool::Warn;
574 my ($buff, $err);
575
576 return 0 unless $raf->Read($buff, 40) == 40;
577 return 0 unless $buff =~ /^FOVb/;
578
579 SetByteOrder('II');
580 $exifTool->SetFileType();
581
582 # check version number
583 my $ver = unpack('x4V',$buff);
584 $ver = ($ver >> 16) . '.' . ($ver & 0xffff);
585 if ($ver >= 3) {
586 &$warn($exifTool, "Can't read version $ver X3F image");
587 return 1;
588 } elsif ($ver > 2.3) {
589 &$warn($exifTool, 'Untested X3F version. Please submit sample for testing', 1);
590 }
591 my $hdrLen = length $buff;
592 # read version 2.1/2.2/2.3 extended header
593 if ($ver > 2) {
594 $hdrLen += $ver > 2.2 ? 64 : 32; # SceneCaptureType string added in 2.3
595 my $more = $hdrLen - length($buff) + 160; # (extended header is 160 bytes)
596 my $buf2;
597 unless ($raf->Read($buf2, $more) == $more) {
598 &$warn($exifTool, 'Error reading extended header');
599 return 1;
600 }
601 $buff .= $buf2;
602 }
603 # extract ImageWidth for later
604 $$exifTool{ImageWidth} = Get32u(\$buff, 28);
605 # process header information
606 my $tagTablePtr = GetTagTable('Image::ExifTool::SigmaRaw::Main');
607 unless ($outfile) {
608 $exifTool->HandleTag($tagTablePtr, 'Header', $buff,
609 DataPt => \$buff,
610 Size => $hdrLen,
611 );
612 }
613 # read the directory pointer
614 $raf->Seek(-4, 2) or &$warn($exifTool, 'Seek error'), return 1;
615 unless ($raf->Read($buff, 4) == 4) {
616 &$warn($exifTool, 'Error reading X3F dir pointer');
617 return 1;
618 }
619 my $offset = unpack('V', $buff);
620 my %dirInfo = (
621 RAF => $raf,
622 DirStart => $offset,
623 );
624 if ($outfile) {
625 $dirInfo{OutFile} = $outfile;
626 $err = WriteX3F($exifTool, \%dirInfo);
627 return -1 if $err and $err eq '-1';
628 } else {
629 # process the X3F subsections
630 $err = $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);
631 }
632 $err and &$warn($exifTool, $err);
633 return 1;
634}
635
6361; # end
637
638__END__
639
640=head1 NAME
641
642Image::ExifTool::SigmaRaw - Read Sigma/Foveon RAW (X3F) meta information
643
644=head1 SYNOPSIS
645
646This module is loaded automatically by Image::ExifTool when required.
647
648=head1 DESCRIPTION
649
650This module contains definitions required by Image::ExifTool to read
651Sigma and Foveon X3F images.
652
653=head1 AUTHOR
654
655Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
656
657This library is free software; you can redistribute it and/or modify it
658under the same terms as Perl itself.
659
660=head1 REFERENCES
661
662=over 4
663
664=item L<http://www.x3f.info/technotes/FileDocs/X3F_Format.pdf>
665
666=back
667
668=head1 SEE ALSO
669
670L<Image::ExifTool::TagNames/SigmaRaw Tags>,
671L<Image::ExifTool::Sigma(3pm)|Image::ExifTool::Sigma>,
672L<Image::ExifTool(3pm)|Image::ExifTool>
673
674=cut
Note: See TracBrowser for help on using the repository browser.