123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668 |
- #------------------------------------------------------------------------------
- # File: SigmaRaw.pm
- #
- # Description: Read Sigma/Foveon RAW (X3F) meta information
- #
- # Revisions: 2005/10/16 - P. Harvey Created
- # 2009/11/30 - P. Harvey Support X3F v2.3 written by Sigma DP2
- #
- # References: 1) http://www.x3f.info/technotes/FileDocs/X3F_Format.pdf
- #------------------------------------------------------------------------------
- package Image::ExifTool::SigmaRaw;
- use strict;
- use vars qw($VERSION);
- use Image::ExifTool qw(:DataAccess :Utils);
- use Image::ExifTool::Sigma;
- $VERSION = '1.24';
- sub ProcessX3FHeader($$$);
- sub ProcessX3FDirectory($$$);
- sub ProcessX3FProperties($$$);
- # main X3F sections (plus header stuff)
- %Image::ExifTool::SigmaRaw::Main = (
- PROCESS_PROC => \&ProcessX3FDirectory,
- NOTES => q{
- These tags are used in Sigma and Foveon RAW (.X3F) images. Metadata is also
- extracted from the JpgFromRaw image if it exists (all models but the SD9 and
- SD10). Currently, metadata may only be written to the embedded JpgFromRaw.
- },
- Header => {
- SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::Header' },
- },
- Header4 => {
- SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::Header4' },
- },
- HeaderExt => {
- SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::HeaderExt' },
- },
- PROP => {
- Name => 'Properties',
- SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::Properties' },
- },
- IMAG => {
- Name => 'PreviewImage',
- Groups => { 2 => 'Preview' },
- Binary => 1,
- },
- IMA2 => [
- {
- Name => 'PreviewImage',
- Condition => 'not $$self{IsJpgFromRaw}',
- Groups => { 2 => 'Preview' },
- Binary => 1,
- },
- {
- Name => 'JpgFromRaw',
- Groups => { 2 => 'Preview' },
- Binary => 1,
- },
- ]
- );
- # common X3F header structure
- %Image::ExifTool::SigmaRaw::Header = (
- PROCESS_PROC => \&ProcessX3FHeader,
- FORMAT => 'int32u',
- NOTES => 'Information extracted from the header of an X3F file.',
- 1 => {
- Name => 'FileVersion',
- ValueConv => '($val >> 16) . "." . ($val & 0xffff)',
- },
- 2 => {
- Name => 'ImageUniqueID',
- # the serial number (with an extra leading "0") makes up
- # the first 8 digits of this UID,
- Format => 'undef[16]',
- ValueConv => 'unpack("H*", $val)',
- },
- 6 => {
- Name => 'MarkBits',
- PrintConv => { BITMASK => { } },
- },
- 7 => 'ImageWidth',
- 8 => 'ImageHeight',
- 9 => 'Rotation',
- 10 => {
- Name => 'WhiteBalance',
- Format => 'string[32]',
- },
- 18 => { #PH (DP2, FileVersion 2.3)
- Name => 'SceneCaptureType',
- Format => 'string[32]',
- },
- );
- # X3F version 4 header structure (ref PH)
- %Image::ExifTool::SigmaRaw::Header4 = (
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
- FORMAT => 'int32u',
- NOTES => 'Header information for version 4.0 or greater X3F.',
- 1 => {
- Name => 'FileVersion',
- ValueConv => '($val >> 16) . "." . ($val & 0xffff)',
- },
- # 8 - undef[4]: 4 random ASCII characters
- 10 => 'ImageWidth',
- 11 => 'ImageHeight',
- 12 => 'Rotation',
- # don't know what the rest of the header contains, but none of
- # these values change in any of my samples...
- );
- # extended header tags
- %Image::ExifTool::SigmaRaw::HeaderExt = (
- GROUPS => { 2 => 'Camera' },
- FORMAT => 'float',
- NOTES => 'Extended header data found in version 2.1 and 2.2 files',
- 0 => 'Unused',
- 1 => { Name => 'ExposureAdjust',PrintConv => 'sprintf("%.1f",$val)' },
- 2 => { Name => 'Contrast', PrintConv => 'sprintf("%.1f",$val)' },
- 3 => { Name => 'Shadow', PrintConv => 'sprintf("%.1f",$val)' },
- 4 => { Name => 'Highlight', PrintConv => 'sprintf("%.1f",$val)' },
- 5 => { Name => 'Saturation', PrintConv => 'sprintf("%.1f",$val)' },
- 6 => { Name => 'Sharpness', PrintConv => 'sprintf("%.1f",$val)' },
- 7 => { Name => 'RedAdjust', PrintConv => 'sprintf("%.1f",$val)' },
- 8 => { Name => 'GreenAdjust', PrintConv => 'sprintf("%.1f",$val)' },
- 9 => { Name => 'BlueAdjust', PrintConv => 'sprintf("%.1f",$val)' },
- 10 => { Name => 'X3FillLight', PrintConv => 'sprintf("%.1f",$val)' },
- );
- # PROP tags
- %Image::ExifTool::SigmaRaw::Properties = (
- PROCESS_PROC => \&ProcessX3FProperties,
- GROUPS => { 2 => 'Camera' },
- PRIORITY => 0, # (because these aren't writable like the EXIF ones)
- AEMODE => {
- Name => 'MeteringMode',
- PrintConv => {
- 8 => '8-segment',
- C => 'Center-weighted average',
- A => 'Average',
- },
- },
- AFAREA => 'AFArea', # observed: CENTER_V
- AFINFOCUS => 'AFInFocus', # observed: H
- AFMODE => 'FocusMode',
- AP_DESC => 'ApertureDisplayed',
- APERTURE => {
- Name => 'FNumber',
- Groups => { 2 => 'Image' },
- PrintConv => 'sprintf("%.1f",$val)',
- },
- BRACKET => 'BracketShot',
- BURST => 'BurstShot',
- CAMMANUF => 'Make',
- CAMMODEL => 'Model',
- CAMNAME => 'CameraName',
- CAMSERIAL => 'SerialNumber',
- CM_DESC => 'SceneCaptureType', #PH (DP2)
- COLORSPACE => 'ColorSpace', # observed: sRGB
- DRIVE => {
- Name => 'DriveMode',
- PrintConv => {
- SINGLE => 'Single Shot',
- MULTI => 'Multi Shot',
- '2S' => '2 s Timer',
- '10S' => '10 s Timer',
- UP => 'Mirror Up',
- AB => 'Auto Bracket',
- OFF => 'Off',
- },
- },
- EVAL_STATE => 'EvalState', # observed: POST-EXPOSURE
- EXPCOMP => {
- Name => 'ExposureCompensation',
- Groups => { 2 => 'Image' },
- PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)',
- },
- EXPNET => {
- Name => 'NetExposureCompensation',
- Groups => { 2 => 'Image' },
- PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)',
- },
- EXPTIME => {
- Name => 'IntegrationTime',
- Groups => { 2 => 'Image' },
- ValueConv => '$val * 1e-6', # convert from usec
- PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
- },
- FIRMVERS => 'FirmwareVersion',
- FLASH => {
- Name => 'FlashMode',
- PrintConv => 'ucfirst(lc($val))',
- },
- FLASHEXPCOMP=> 'FlashExpComp',
- FLASHPOWER => 'FlashPower',
- FLASHTTLMODE=> 'FlashTTLMode', # observed: ON
- FLASHTYPE => 'FlashType', # observed: NONE
- FLENGTH => {
- Name => 'FocalLength',
- PrintConv => 'sprintf("%.1f mm",$val)',
- },
- FLEQ35MM => {
- Name => 'FocalLengthIn35mmFormat',
- PrintConv => 'sprintf("%.1f mm",$val)',
- },
- FOCUS => {
- Name => 'Focus',
- PrintConv => {
- AF => 'Auto-focus Locked',
- 'NO LOCK' => "Auto-focus Didn't Lock",
- M => 'Manual',
- },
- },
- IMAGERBOARDID => 'ImagerBoardID',
- IMAGERTEMP => {
- Name => 'SensorTemperature',
- PrintConv => '"$val C"',
- },
- IMAGEBOARDID=> 'ImageBoardID', #PH (DP2)
- ISO => 'ISO',
- LENSARANGE => 'LensApertureRange',
- LENSFRANGE => 'LensFocalRange',
- LENSMODEL => {
- Name => 'LensType',
- ValueConvInv => '$val=~s/\.\d+$//; $val', # (truncate decimal part)
- PrintConv => \%Image::ExifTool::Sigma::sigmaLensTypes,
- SeparateTable => 'Sigma LensType',
- },
- PMODE => {
- Name => 'ExposureProgram',
- PrintConv => {
- P => 'Program',
- A => 'Aperture Priority',
- S => 'Shutter Priority',
- M => 'Manual',
- },
- },
- RESOLUTION => {
- Name => 'Quality',
- PrintConv => {
- LOW => 'Low',
- MED => 'Medium',
- HI => 'High',
- },
- },
- SENSORID => 'SensorID',
- SH_DESC => 'ShutterSpeedDisplayed',
- SHUTTER => {
- Name => 'ExposureTime',
- Groups => { 2 => 'Image' },
- PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
- },
- TIME => {
- Name => 'DateTimeOriginal',
- Groups => { 2 => 'Time' },
- Description => 'Date/Time Original',
- ValueConv => 'ConvertUnixTime($val)',
- PrintConv => '$self->ConvertDateTime($val)',
- },
- WB_DESC => 'WhiteBalance',
- VERSION_BF => 'VersionBF',
- );
- #------------------------------------------------------------------------------
- # Extract null-terminated unicode string from list of characters
- # Inputs: 0) ExifTool ref, 1) list ref, 2) position in list
- # Returns: Converted string
- sub ExtractUnicodeString($$$)
- {
- my ($et, $chars, $pos) = @_;
- my $i;
- for ($i=$pos; $i<@$chars; ++$i) {
- last unless $$chars[$i];
- }
- my $buff = pack('v*', @$chars[$pos..$i-1]);
- return $et->Decode($buff, 'UCS2', 'II');
- }
- #------------------------------------------------------------------------------
- # Process an X3F header
- # Inputs: 0) ExifTool ref, 1) DirInfo ref, 2) tag table ref
- # Returns: 1 on success
- sub ProcessX3FHeader($$$)
- {
- my ($et, $dirInfo, $tagTablePtr) = @_;
- my $dataPt = $$dirInfo{DataPt};
- my $hdrLen = $$dirInfo{DirLen};
- # process the static header structure first
- $et->ProcessBinaryData($dirInfo, $tagTablePtr);
- # process extended data if available
- if (length($$dataPt) - $hdrLen >= 160) {
- my $verbose = $et->Options('Verbose');
- if ($verbose) {
- $et->VerboseDir('X3F HeaderExt', 32);
- HexDump($dataPt, undef,
- MaxLen => $verbose > 3 ? 1024 : 96,
- Out => $et->Options('TextOut'),
- Prefix => $$et{INDENT},
- Start => $hdrLen,
- ) if $verbose > 2;
- }
- $tagTablePtr = GetTagTable('Image::ExifTool::SigmaRaw::HeaderExt');
- my @tags = unpack("x${hdrLen}C32", $$dataPt);
- my $i;
- my $unused = 0;
- for ($i=0; $i<32; ++$i) {
- $tags[$i] or ++$unused, next;
- $et->HandleTag($tagTablePtr, $tags[$i], undef,
- Index => $i,
- DataPt => $dataPt,
- Start => $hdrLen + 32 + $i * 4,
- Size => 4,
- );
- }
- $et->VPrint(0, "$$et{INDENT}($unused entries unused)\n");
- }
- return 1;
- }
- #------------------------------------------------------------------------------
- # Process an X3F properties
- # Inputs: 0) ExifTool ref, 1) DirInfo ref, 2) tag table ref
- # Returns: 1 on success
- sub ProcessX3FProperties($$$)
- {
- my ($et, $dirInfo, $tagTablePtr) = @_;
- my $dataPt = $$dirInfo{DataPt};
- my $size = length($$dataPt);
- my $verbose = $et->Options('Verbose');
- my $unknown = $et->Options('Unknown');
- unless ($size >= 24 and $$dataPt =~ /^SECp/) {
- $et->Warn('Bad properties header');
- return 0;
- }
- my ($entries, $fmt, $len) = unpack('x8V2x4V', $$dataPt);
- unless ($size >= 24 + 8 * $entries + $len) {
- $et->Warn('Truncated Property directory');
- return 0;
- }
- $verbose and $et->VerboseDir('Properties', $entries);
- $fmt == 0 or $et->Warn("Unsupported character format $fmt"), return 0;
- my $charPos = 24 + 8 * $entries;
- my @chars = unpack('v*',substr($$dataPt, $charPos, $len * 2));
- my $index;
- for ($index=0; $index<$entries; ++$index) {
- my ($namePos, $valPos) = unpack('V2',substr($$dataPt, $index*8 + 24, 8));
- if ($namePos >= @chars or $valPos >= @chars) {
- $et->Warn('Bad Property pointer');
- return 0;
- }
- my $tag = ExtractUnicodeString($et, \@chars, $namePos);
- my $val = ExtractUnicodeString($et, \@chars, $valPos);
- if (not $$tagTablePtr{$tag} and $unknown and $tag =~ /^\w+$/) {
- my $tagInfo = {
- Name => "SigmaRaw_$tag",
- Description => Image::ExifTool::MakeDescription('SigmaRaw', $tag),
- Unknown => 1,
- Writable => 0, # can't write unknown tags
- };
- # add tag information to table
- AddTagToTable($tagTablePtr, $tag, $tagInfo);
- }
- $et->HandleTag($tagTablePtr, $tag, $val,
- Index => $index,
- DataPt => $dataPt,
- Start => $charPos + 2 * $valPos,
- Size => 2 * (length($val) + 1),
- );
- }
- return 1;
- }
- #------------------------------------------------------------------------------
- # Write an X3F file
- # Inputs: 0) ExifTool ref, 1) DirInfo ref (DirStart = directory offset)
- # Returns: error string, undef on success, or -1 on write error
- # Notes: Writes metadata to embedded JpgFromRaw image
- sub WriteX3F($$)
- {
- my ($et, $dirInfo) = @_;
- my $raf = $$dirInfo{RAF};
- my $outfile = $$dirInfo{OutFile};
- my ($outDir, $buff, $ver, $entries, $dir, $outPos, $index, $didContain);
- $raf->Seek($$dirInfo{DirStart}, 0) or return 'Error seeking to directory start';
- # read the X3F directory header (will be copied directly to output)
- $raf->Read($outDir, 12) == 12 or return 'Truncated X3F image';
- $outDir =~ /^SECd/ or return 'Bad section header';
- ($ver, $entries) = unpack('x4V2', $outDir);
- # do sanity check on number of entries in directory
- return 'Invalid X3F directory count' unless $entries > 2 and $entries < 20;
- # read the directory entries
- unless ($raf->Read($dir, $entries * 12) == $entries * 12) {
- return 'Truncated X3F directory';
- }
- # do a quick scan to determine the offset of the first data subsection
- for ($index=0; $index<$entries; ++$index) {
- my $pos = $index * 12;
- my ($offset, $len, $tag) = unpack("x${pos}V2a4", $dir);
- # remember position of first data subsection
- $outPos = $offset if not defined $outPos or $outPos > $offset;
- }
- # copy the file header up to the start of the first data subsection
- unless ($raf->Seek(0,0) and $raf->Read($buff, $outPos) == $outPos) {
- return 'Error reading X3F header';
- }
- Write($outfile, $buff) or return -1;
- # loop through directory, rewriting each section
- for ($index=0; $index<$entries; ++$index) {
- my $pos = $index * 12;
- my ($offset, $len, $tag) = unpack("x${pos}V2a4", $dir);
- $raf->Seek($offset, 0) or return 'Bad data offset';
- if ($tag eq 'IMA2' and $len > 28) {
- # check subsection header (28 bytes) to see if this is a JPEG preview image
- $raf->Read($buff, 28) == 28 or return 'Error reading PreviewImage header';
- Write($outfile, $buff) or return -1;
- $len -= 28;
- # only rewrite full-sized JpgFromRaw (version 2.0, type 2, format 18)
- if ($buff =~ /^SECi\0\0\x02\0\x02\0\0\0\x12\0\0\0/ and
- $$et{ImageWidth} == unpack('x16V', $buff))
- {
- $raf->Read($buff, $len) == $len or return 'Error reading JpgFromRaw';
- # use same write directories as JPEG
- $et->InitWriteDirs('JPEG');
- # rewrite the embedded JPEG in memory
- my $newData;
- my %jpegInfo = (
- Parent => 'X3F',
- RAF => new File::RandomAccess(\$buff),
- OutFile => \$newData,
- );
- $$et{FILE_TYPE} = 'JPEG';
- my $success = $et->WriteJPEG(\%jpegInfo);
- $$et{FILE_TYPE} = 'X3F';
- SetByteOrder('II');
- return 'Error writing X3F JpgFromRaw' unless $success and $newData;
- return -1 if $success < 0;
- # write new data if anything changed, otherwise copy old image
- my $outPt = $$et{CHANGED} ? \$newData : \$buff;
- Write($outfile, $$outPt) or return -1;
- # set $len to the total subsection data length
- $len = length($$outPt) + 28;
- $didContain = 1;
- } else {
- # copy original image data
- Image::ExifTool::CopyBlock($raf, $outfile, $len) or return 'Corrupted X3F image';
- $len += 28;
- }
- } else {
- # copy data for this subsection
- Image::ExifTool::CopyBlock($raf, $outfile, $len) or return 'Corrupted X3F directory';
- }
- # add directory entry and update output file position
- $outDir .= pack('V2a4', $outPos, $len, $tag);
- $outPos += $len;
- # pad data to an even 4-byte boundary
- if ($len & 0x03) {
- my $pad = 4 - ($len & 0x03);
- Write($outfile, "\0" x $pad) or return -1;
- $outPos += $pad;
- }
- }
- # warn if we couldn't add metadata to this image (should only be SD9 or SD10)
- $didContain or $et->Warn("Can't yet write SD9 or SD10 X3F images");
- # write out the directory and the directory pointer, and we are done
- Write($outfile, $outDir, pack('V', $outPos)) or return -1;
- return undef;
- }
- #------------------------------------------------------------------------------
- # Process an X3F directory
- # Inputs: 0) ExifTool ref, 1) DirInfo ref, 2) tag table ref
- # Returns: error string or undef on success
- sub ProcessX3FDirectory($$$)
- {
- my ($et, $dirInfo, $tagTablePtr) = @_;
- my $raf = $$dirInfo{RAF};
- my $verbose = $et->Options('Verbose');
- $raf->Seek($$dirInfo{DirStart}, 0) or return 'Error seeking to directory start';
- # parse the X3F directory structure
- my ($buff, $ver, $entries, $index, $dir);
- $raf->Read($buff, 12) == 12 or return 'Truncated X3F image';
- $buff =~ /^SECd/ or return 'Bad section header';
- ($ver, $entries) = unpack('x4V2', $buff);
- $verbose and $et->VerboseDir('X3F Subsection', $entries);
- $raf->Read($dir, $entries * 12) == $entries * 12 or return 'Truncated X3F directory';
- for ($index=0; $index<$entries; ++$index) {
- my $pos = $index * 12;
- my ($offset, $len, $tag) = unpack("x${pos}V2a4", $dir);
- my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
- if ($verbose) {
- $et->VPrint(0, "$$et{INDENT}$index) $tag Subsection ($len bytes):\n");
- if ($verbose > 2) {
- $raf->Seek($offset, 0) or return 'Error seeking';
- $raf->Read($buff, $len) == $len or return 'Truncated image';
- $et->VerboseDump(\$buff);
- }
- }
- next unless $tagInfo;
- $raf->Seek($offset, 0) or return "Error seeking for $$tagInfo{Name}";
- if ($$tagInfo{Name} eq 'PreviewImage') {
- # check image header to see if this is a JPEG preview image
- $raf->Read($buff, 28) == 28 or return 'Error reading PreviewImage header';
- # ignore all image data but JPEG compressed (version 2.0, type 2, format 18)
- next unless $buff =~ /^SECi\0\0\x02\0\x02\0\0\0\x12\0\0\0/;
- # check preview image size and extract full-sized preview as JpgFromRaw
- if ($$et{ImageWidth} == unpack('x16V', $buff)) {
- $$et{IsJpgFromRaw} = 1;
- $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
- delete $$et{IsJpgFromRaw};
- }
- $offset += 28;
- $len -= 28;
- }
- $raf->Read($buff, $len) == $len or return "Error reading $$tagInfo{Name} data";
- my $subdir = $$tagInfo{SubDirectory};
- if ($subdir) {
- my %dirInfo = ( DataPt => \$buff );
- my $subTable = GetTagTable($$subdir{TagTable});
- $et->ProcessDirectory(\%dirInfo, $subTable);
- } else {
- # extract metadata from JpgFromRaw
- if ($$tagInfo{Name} eq 'JpgFromRaw') {
- my %dirInfo = (
- Parent => 'X3F',
- RAF => new File::RandomAccess(\$buff),
- );
- $$et{BASE} += $offset;
- $et->ProcessJPEG(\%dirInfo);
- $$et{BASE} -= $offset;
- SetByteOrder('II');
- }
- $et->FoundTag($tagInfo, $buff);
- }
- }
- return undef;
- }
- #------------------------------------------------------------------------------
- # Read/write information from a Sigma raw (X3F) image
- # Inputs: 0) ExifTool ref, 1) DirInfo ref
- # Returns: 1 on success, 0 if this wasn't a valid X3F image, or -1 on write error
- sub ProcessX3F($$)
- {
- my ($et, $dirInfo) = @_;
- my $outfile = $$dirInfo{OutFile};
- my $raf = $$dirInfo{RAF};
- my $warn = $outfile ? \&Image::ExifTool::Error : \&Image::ExifTool::Warn;
- my ($buff, $err, $hdrLen);
- return 0 unless $raf->Read($buff, 40) == 40;
- return 0 unless $buff =~ /^FOVb/;
- SetByteOrder('II');
- $et->SetFileType();
- # check version number
- my $ver = unpack('x4V',$buff);
- $ver = ($ver >> 16) . '.' . ($ver & 0xffff);
- if ($ver > 5) {
- &$warn($et, "Untested X3F version ($ver). Please submit sample for testing", 1);
- }
- # read version 2.1/2.2/2.3 extended header
- if ($ver > 2) {
- my ($extra, $buf2);
- if ($ver >= 4) {
- $hdrLen = 0x300;
- $extra = 0;
- } else {
- $hdrLen = $ver > 2.2 ? 104 : 72; # SceneCaptureType string added in 2.3
- $extra = 160; # (extended header is 160 bytes)
- }
- my $more = $hdrLen - length($buff) + $extra;
- unless ($raf->Read($buf2, $more) == $more) {
- &$warn($et, 'Error reading X3F header');
- return 1;
- }
- $buff .= $buf2;
- }
- my ($widPos, $hdrType) = $ver < 4 ? (28, 'Header') : (40, 'Header4');
- # extract ImageWidth for later
- $$et{ImageWidth} = Get32u(\$buff, $widPos);
- # process header information
- my $tagTablePtr = GetTagTable('Image::ExifTool::SigmaRaw::Main');
- unless ($outfile) {
- $et->HandleTag($tagTablePtr, $hdrType, $buff,
- DataPt => \$buff,
- Size => $hdrLen,
- );
- }
- # read the directory pointer
- $raf->Seek(-4, 2) or &$warn($et, 'Seek error'), return 1;
- unless ($raf->Read($buff, 4) == 4) {
- &$warn($et, 'Error reading X3F dir pointer');
- return 1;
- }
- my $offset = unpack('V', $buff);
- my %dirInfo = (
- RAF => $raf,
- DirStart => $offset,
- );
- if ($outfile) {
- $dirInfo{OutFile} = $outfile;
- $err = WriteX3F($et, \%dirInfo);
- return -1 if $err and $err eq '-1';
- } else {
- # process the X3F subsections
- $err = $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
- }
- $err and &$warn($et, $err);
- return 1;
- }
- 1; # end
- __END__
- =head1 NAME
- Image::ExifTool::SigmaRaw - Read Sigma/Foveon RAW (X3F) meta information
- =head1 SYNOPSIS
- This module is loaded automatically by Image::ExifTool when required.
- =head1 DESCRIPTION
- This module contains definitions required by Image::ExifTool to read
- Sigma and Foveon X3F images.
- =head1 AUTHOR
- Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
- This library is free software; you can redistribute it and/or modify it
- under the same terms as Perl itself.
- =head1 REFERENCES
- =over 4
- =item L<http://www.x3f.info/technotes/FileDocs/X3F_Format.pdf>
- =back
- =head1 SEE ALSO
- L<Image::ExifTool::TagNames/SigmaRaw Tags>,
- L<Image::ExifTool::Sigma(3pm)|Image::ExifTool::Sigma>,
- L<Image::ExifTool(3pm)|Image::ExifTool>
- =cut
|