Ignore:
Timestamp:
2011-06-01T12:33:42+12:00 (13 years ago)
Author:
sjm84
Message:

Updating the ExifTool perl modules

File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone2/perllib/cpan/Image/ExifTool/SigmaRaw.pm

    r16842 r24107  
    44# Description:  Read Sigma/Foveon RAW (X3F) meta information
    55#
    6 # Revisions:    10/16/2005 - P. Harvey Created
     6# Revisions:    2005/10/16 - P. Harvey Created
     7#               2009/11/30 - P. Harvey Support X3F v2.3 written by Sigma DP2
    78#
    89# References:   1) http://www.x3f.info/technotes/FileDocs/X3F_Format.pdf
     
    1516use Image::ExifTool qw(:DataAccess :Utils);
    1617
    17 $VERSION = '1.03';
     18$VERSION = '1.14';
    1819
    1920sub ProcessX3FHeader($$$);
     
    2122sub ProcessX3FProperties($$$);
    2223
     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
    2345# main X3F sections (plus header stuff)
    2446%Image::ExifTool::SigmaRaw::Main = (
    2547    PROCESS_PROC => \&ProcessX3FDirectory,
    26     NOTES => 'These tags are used in Sigma and Foveon RAW (.X3F) images.',
     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    },
    2753    Header => {
    2854        SubDirectory => { TagTable => 'Image::ExifTool::SigmaRaw::Header' },
     
    3965        Binary => 1,
    4066    },
    41     IMA2 => {
    42         Name => 'PreviewImage',
    43         Binary => 1,
    44     },
     67    IMA2 => [
     68        {
     69            Name => 'PreviewImage',
     70            Condition => 'not $$self{IsJpgFromRaw}',
     71            Binary => 1,
     72        },
     73        {
     74            Name => 'JpgFromRaw',
     75            Binary => 1,
     76        },
     77    ]
    4578);
    4679
     
    5386        ValueConv => '($val >> 16) . "." . ($val & 0xffff)',
    5487    },
     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    },
    5599    7 => 'ImageWidth',
    56100    8 => 'ImageHeight',
     
    60104        Format => 'string[32]',
    61105    },
     106    18 => { #PH (DP2, FileVersion 2.3)
     107        Name => 'SceneCaptureType',
     108        Format => 'string[32]',
     109    },
    62110);
    63111
     
    67115    NOTES => 'Extended header data found in version 2.1 and 2.2 files',
    68116    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)' },
     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)' },
    79127);
    80128
     
    106154    CAMNAME     => 'CameraName',
    107155    CAMSERIAL   => 'SerialNumber',
     156    CM_DESC     => 'SceneCaptureType', #PH (DP2)
    108157    COLORSPACE  => 'ColorSpace', # observed: sRGB
    109158    DRIVE => {
     
    112161            SINGLE => 'Single Shot',
    113162            MULTI  => 'Multi Shot',
    114             '2S'   => '2-sec Timer',
    115             '10S'  => '10-sec Timer',
     163            '2S'   => '2 s Timer',
     164            '10S'  => '10 s Timer',
    116165            UP     => 'Mirror Up',
    117166            AB     => 'Auto Bracket',
     
    123172        Name => 'ExposureCompensation',
    124173        Groups => { 2 => 'Image' },
    125         PrintConv => 'Image::ExifTool::Exif::ConvertFraction($val)',
     174        PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)',
    126175    },
    127176    EXPNET => {
    128177        Name => 'NetExposureCompensation',
    129178        Groups => { 2 => 'Image' },
    130         PrintConv => 'Image::ExifTool::Exif::ConvertFraction($val)',
     179        PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)',
    131180    },
    132181    EXPTIME => {
     
    147196    FLENGTH => {
    148197        Name => 'FocalLength',
    149         PrintConv => 'sprintf("%.1fmm",$val)',
    150     },
    151     FLEQ35MM    => 'FocalLengthIn35mmFormat',
     198        PrintConv => 'sprintf("%.1f mm",$val)',
     199    },
     200    FLEQ35MM => {
     201        Name => 'FocalLengthIn35mmFormat',
     202        PrintConv => 'sprintf("%.1f mm",$val)',
     203    },
    152204    FOCUS => {
    153205        Name => 'Focus',
     
    159211    },
    160212    IMAGERBOARDID => 'ImagerBoardID',
    161     IMAGERTEMP  => 'SensorTemperature',
     213    IMAGERTEMP  => {
     214        Name => 'SensorTemperature',
     215        PrintConv => '"$val C"',
     216    },
     217    IMAGEBOARDID=> 'ImageBoardID', #PH (DP2)
    162218    ISO         => 'ISO',
    163219    LENSARANGE  => 'LensApertureRange',
    164220    LENSFRANGE  => 'LensFocalRange',
    165     LENSMODEL   => 'LensID',
     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    },
    166230    PMODE => {
    167231        Name => 'ExposureProgram',
     
    210274        last unless $$chars[$i];
    211275    }
    212     my $buff = pack('v*',@$chars[$pos..$i-1]);
    213     my $val = $exifTool->Unicode2Charset($buff, 'II');
    214     return $val;
     276    my $buff = pack('v*', @$chars[$pos..$i-1]);
     277    return $exifTool->Decode($buff, 'UCS2', 'II');
    215278}
    216279
     
    222285{
    223286    my ($exifTool, $dirInfo, $tagTablePtr) = @_;
     287    my $dataPt = $$dirInfo{DataPt};
     288    my $hdrLen = $$dirInfo{DirLen};
    224289    my $verbose = $exifTool->Options('Verbose');
    225290
     
    228293
    229294    # process extended data if available
    230     if ($$dirInfo{DirLen} >= 232) {
    231         $verbose and $exifTool->VerboseDir('X3F HeaderExt', 32);
     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        }
    232305        $tagTablePtr = GetTagTable('Image::ExifTool::SigmaRaw::HeaderExt');
    233         my $dataPt = $$dirInfo{DataPt};
    234         my @vals = unpack('x72C32V32', $$dataPt);
     306        my @vals = unpack("x${hdrLen}C32V32", $$dataPt);
    235307        my $i;
    236308        my $unused = 0;
     
    250322            }
    251323            $exifTool->HandleTag($tagTablePtr, $vals[$i], $val,
    252                 Index => $i,
     324                Index  => $i,
    253325                DataPt => $dataPt,
    254                 Start => 104 + $i * 4,
    255                 Size => 4,
     326                Start  => $hdrLen + 32 + $i * 4,
     327                Size   => 4,
    256328            );
    257329        }
     
    305377            Image::ExifTool::AddTagToTable($tagTablePtr, $tag, $tagInfo);
    306378        }
    307        
     379
    308380        $exifTool->HandleTag($tagTablePtr, $tag, $val,
    309381            Index => $index,
     
    314386    }
    315387    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;
    316491}
    317492
     
    329504
    330505    # parse the X3F directory structure
    331     my ($buff, $ver, $entries, $index);
     506    my ($buff, $ver, $entries, $index, $dir);
    332507    $raf->Read($buff, 12) == 12 or return 'Truncated X3F image';
    333508    $buff =~ /^SECd/ or return 'Bad section header';
    334509    ($ver, $entries) = unpack('x4V2', $buff);
    335510    $verbose and $exifTool->VerboseDir('X3F Subsection', $entries);
    336     my $dir;
    337511    $raf->Read($dir, $entries * 12) == $entries * 12 or return 'Truncated X3F directory';
    338512    for ($index=0; $index<$entries; ++$index) {
     
    344518            if ($verbose > 2) {
    345519                $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                 );
     520                $raf->Read($buff, $len) == $len or return 'Truncated image';
     521                $exifTool->VerboseDump(\$buff);
    353522            }
    354523        }
     
    358527            # check image header to see if this is a JPEG preview image
    359528            $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;
     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;
    362538            $len -= 28;
    363539        }
     
    369545            $exifTool->ProcessDirectory(\%dirInfo, $subTable);
    370546        } 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            }
    371558            $exifTool->FoundTag($tagInfo, $buff);
    372559        }
     
    376563
    377564#------------------------------------------------------------------------------
    378 # Extract information from a Sigma raw (X3F) image
     565# Read/write information from a Sigma raw (X3F) image
    379566# Inputs: 0) ExifTool object reference, 1) DirInfo reference
    380 # Returns: 1 on success, 0 if this wasn't a valid X3F image
     567# Returns: 1 on success, 0 if this wasn't a valid X3F image, or -1 on write error
    381568sub ProcessX3F($$)
    382569{
    383570    my ($exifTool, $dirInfo) = @_;
     571    my $outfile = $$dirInfo{OutFile};
    384572    my $raf = $$dirInfo{RAF};
    385     my $buff;
     573    my $warn = $outfile ? \&Image::ExifTool::Error : \&Image::ExifTool::Warn;
     574    my ($buff, $err);
    386575
    387576    return 0 unless $raf->Read($buff, 40) == 40;
     
    395584    $ver = ($ver >> 16) . '.' . ($ver & 0xffff);
    396585    if ($ver >= 3) {
    397         $exifTool->Warn("Can't read version $ver X3F image");
     586        &$warn($exifTool, "Can't read version $ver X3F image");
    398587        return 1;
    399     }
    400     # read version 2.1/2.2 extended header
     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
    401593    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)
    402596        my $buf2;
    403         unless ($raf->Read($buf2, 192) == 192) {
    404             $exifTool->Warn('Error reading extended header');
     597        unless ($raf->Read($buf2, $more) == $more) {
     598            &$warn($exifTool, 'Error reading extended header');
    405599            return 1;
    406600        }
    407601        $buff .= $buf2;
    408602    }
     603    # extract ImageWidth for later
     604    $$exifTool{ImageWidth} = Get32u(\$buff, 28);
    409605    # process header information
    410606    my $tagTablePtr = GetTagTable('Image::ExifTool::SigmaRaw::Main');
    411     my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, 'Header');
    412     my $subdir = GetTagTable('Image::ExifTool::SigmaRaw::Header');
     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);
    413620    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 = (
    427621        RAF => $raf,
    428622        DirStart => $offset,
    429623    );
    430     # process the X3F subsections
    431     my $err = $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);
    432     $err and $exifTool->Warn($err);
     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);
    433633    return 1;
    434634}
     
    453653=head1 AUTHOR
    454654
    455 Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
     655Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
    456656
    457657This library is free software; you can redistribute it and/or modify it
Note: See TracChangeset for help on using the changeset viewer.