Image-ExifTool

 view release on metacpan or  search on metacpan

lib/Image/ExifTool/Sony.pm  view on Meta::CPAN

        Format => 'string',
        ValueConv => 'Image::ExifTool::Exif::ExifDate($val)',
    },
    0xe000 => { Name => 'Sony_rtmd_0xe000', Format => 'int8u',  %hidUnk }, # (16 bytes)
    0xe300 => { Name => 'Sony_rtmd_0xe300', Format => 'int8u',  %hidUnk }, # seen: 0,1
    0xe301 => { Name => 'Sony_rtmd_0xe301', Format => 'int32u', %hidUnk }, # seen: 100,1600,12800 - ISO
    0xe302 => { Name => 'Sony_rtmd_0xe302', Format => 'int8u',  %hidUnk }, # seen: 1
    0xe303 => { #forum12218
        Name => 'WhiteBalance',
        Format => 'int8u',
        PrintConv => {
            1 => 'Incandescent',
            2 => 'Fluorescent',
            4 => 'Daylight',
            5 => 'Cloudy',
            6 => 'Custom', # ("Shade" uses this value too)
            255 => 'Preset',
        },
    },
    0xe304 => {
        Name => 'DateTime',
        Groups => { 2 => 'Time' },
        Format => 'undef',
        ValueConv => 'my @a=unpack("x1H4H2H2H2H2H2",$val); "$a[0]:$a[1]:$a[2] $a[3]:$a[4]:$a[5]"',
        PrintConv => '$self->ConvertDateTime($val)',
    },
    0xe435 => { Name => 'Sony_rtmd_0xe435', Format => 'int32u',  %hidUnk }, # seen: 2000
    0xe437 => { Name => 'Sony_rtmd_0xe437', Format => 'int32s',  %hidUnk }, # seen: -3800 to -3400
    0xe43b => {
        Name => 'PitchRollYaw',
        Format => 'int16s',
        RawConv => 'substr($val, 8)',
    },
    0xe445 => { Name => 'Sony_rtmd_0xe445', Format => 'int32u',  %hidUnk }, # seen: 2000
    0xe44b => {
        Name => 'Accelerometer', # (NC)
        Format => 'int16s',
        RawConv => 'substr($val, 8)',
    },
    # f010 - 2048 bytes
    # f020 - 543 bytes
);

# Composite Sony tags
%Image::ExifTool::Sony::Composite = (
    GROUPS => { 2 => 'Camera' },
    FocusDistance => {
        Require => {
            0 => 'Sony:FocusPosition',
            1 => 'FocalLength',
        },
        Notes => 'distance in metres = FocusPosition * FocalLength / 1000',
        ValueConv => '$val >= 128 ? "inf" : $val * $val[1] / 1000',
        PrintConv => '$val eq "inf" ? $val : "$val m"',
    },
    FocusDistance2 => {
        # For DSLR-A550 and newer, NEX/ILCE/SLT/ILCA (only A65V/A77V are missing ...):
        #     seen FocusPosition2 with values from 80 - 255 (and 21 for Touit 12mm...)
        # Formula from minolta.pm (WBInfoA100 - 0x49bb) gives mostly correct/acceptable distance indications.
            # (https://exiftool.org/forum/index.php/topic,3688.0.html)
            # if this value is the 35mm equivalent magnification, then the formula could
            # be (1.5 * 2**($val/16-5)+1) * FocalLength, but this tends to underestimate
            # distance by about 18% (ref 20) (255=inf)
            # modified 16-10-2014 based on A99V measurements: use FocalLengthIn35mmFormat and leave out the "1.5*" factor.
        Require => {
            0 => 'Sony:FocusPosition2',
            1 => 'FocalLengthIn35mmFormat',
        },
        # (NOTE: This calculation may be wrong. "Focus Distance 2 is the result of an erroneous
        #  user supplied formula to exiftool. It does use data embedded in the raw file,
        #  but it is not the data. The actual embedded data seems to be proportional to
        #  magnification not a focus distance. The camera needs to calculate magnification
        #  for translation stabilization.", ref https://www.fredmiranda.com/forum/topic/1858744/0)
        ValueConv => q{
            return undef unless $val;
            return 'inf' if $val >= 255;
            return (2**($val/16-5) + 1) * $val[1] / 1000;
        },
        PrintConv => '$val eq "inf" ? $val : sprintf("%.4g m", $val)',
    },
    GPSDateTime => {
        Description => 'GPS Date/Time',
        Groups => { 2 => 'Time' },
        SubDoc => 1,    # generate for all sub-documents
        Require => {
            0 => 'Sony:GPSDateStamp',
            1 => 'Sony:GPSTimeStamp',
        },
        ValueConv => '"$val[0] $val[1]Z"',
        PrintConv => '$self->ConvertDateTime($val)',
    },
    GPSLatitude => {
        SubDoc => 1,    # generate for all sub-documents
        Groups => { 2 => 'Location' },
        Require => {
            0 => 'Sony:GPSLatitude',
            1 => 'Sony:GPSLatitudeRef',
        },
        ValueConv => '$val[1] =~ /^S/i ? -$val[0] : $val[0]',
        PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
    },
    GPSLongitude => {
        SubDoc => 1,    # generate for all sub-documents
        Groups => { 2 => 'Location' },
        Require => {
            0 => 'Sony:GPSLongitude',
            1 => 'Sony:GPSLongitudeRef',
        },
        ValueConv => '$val[1] =~ /^W/i ? -$val[0] : $val[0]',
        PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
    },
    HiddenData => {
        Require => {
            # (Note: This pointer is fragile in JPEG images, and won't be updated
            # when the file is written unless the EXIF information is also written, but
            # an incorrect offset is fixed by subsequently writing EXIF with ExifTool)
            0 => 'Sony:HiddenDataOffset',
            1 => 'Sony:HiddenDataLength',
        },
        Notes => q{
            hidden data in some Sony JPG and ARW images, extracted only if specifically
            requested
        },
        RawConv => q{
            my $hdOff = $val[0];
            my $reqTag = $$self{REQ_TAG_LOOKUP}{hiddendata};
            my $hDump = $self->Options('HtmlDump');
            return undef unless $reqTag or $self->Options('Validate') or $hDump;
            my $dataPt = Image::ExifTool::Sony::ReadHiddenData($self, $hdOff, $val[1]);
            if ($dataPt and $hDump) {

lib/Image/ExifTool/Sony.pm  view on Meta::CPAN

    if ($entry{0x201} and $$et{A100PreviewStart} and
        $entry{0x202} and $$et{A100PreviewLength})
    {
        Set32u($$et{A100PreviewStart}, $dataPt, $entry{0x201} + 8);
        Set32u($$et{A100PreviewLength}, $dataPt, $entry{0x202} + 8);
    }
    # write TIFF IFD structure
    my $outfile = $$dirInfo{OutFile};
    my $header = GetByteOrder() . Set16u(0x2a) . Set32u(8);
    Write($outfile, $header, $$dataPt) or return 'Error writing';
    # copy over image data
    if (ref $imageData) {
        $et->CopyImageData($imageData, $outfile) or return 'Error copying image data';
    }
    # write MRW data if necessary
    if ($$et{MRWDirData}) {
        Write($outfile, "\0" x $pad) if $pad;   # write padding if necessary
        Write($outfile, $$et{MRWDirData});
        delete $$et{MRWDirData};
        # set TIFF_END to copy over the MRW image data
        $$et{TIFF_END} = $dataOffset if $dataOffset;
    }
    return undef;
}

#------------------------------------------------------------------------------
# Decrypt/Encrypt Sony data (ref 1) (reversible encryption)
# Inputs: 0) data reference, 1) start offset, 2) data length, 3) decryption key
# Returns: nothing (original data buffer is updated with decrypted data)
# Notes: data length should be a multiple of 4
sub Decrypt($$$$)
{
    my ($dataPt, $start, $len, $key) = @_;
    my ($i, $j, @pad);
    my $words = int ($len / 4);

    for ($i=0; $i<4; ++$i) {
        my $lo = ($key & 0xffff) * 0x0edd + 1;
        my $hi = ($key >> 16) * 0x0edd + ($key & 0xffff) * 0x02e9 + ($lo >> 16);
        $pad[$i] = $key = (($hi & 0xffff) << 16) + ($lo & 0xffff);
    }
    $pad[3] = ($pad[3] << 1 | ($pad[0]^$pad[2]) >> 31) & 0xffffffff;
    for ($i=4; $i<0x7f; ++$i) {
        $pad[$i] = (($pad[$i-4]^$pad[$i-2]) << 1 |
                    ($pad[$i-3]^$pad[$i-1]) >> 31) & 0xffffffff;
    }
    my @data = unpack("x$start N$words", $$dataPt);
    for ($i=0x7f,$j=0; $j<$words; ++$i,++$j) {
        $data[$j] ^= $pad[$i & 0x7f] = $pad[($i+1) & 0x7f] ^ $pad[($i+65) & 0x7f];
    }
    substr($$dataPt, $start, $words*4) = pack('N*', @data);
}

#------------------------------------------------------------------------------
# Decipher/encipher Sony tag 0x2010, 0x900b, 0x9050 and 0x940x data (ref PH)
# Inputs: 0) data reference, 1) true to encipher the data
sub Decipher($;$)
{
    my ($dataPt, $encipher) = @_;
    # This is a simple substitution cipher, so use a hardcoded translation table for speed.
    # The formula is: $c = ($b*$b*$b) % 249, where $c is the enciphered data byte
    # (note that bytes with values 249-255 are not translated, and 0-1, 82-84,
    #  165-167 and 248 have the same enciphered value)
    if ($encipher) {    # encipher
        $$dataPt =~ tr/\x02-\xf7/\x08\x1b\x40\x7d\xd8\x5e\x0e\xe7\x04V\xea\xcd\x05\x8ap\xb6i\x88\x200\xbe\xd7\x81\xbb\x92\x0c\x28\xecl\xa0\x95Q\xd3\x2f\x5dj\x5c9\x07\xc5\x87L\x1a\xf0\xe2\xef\x24y\x02\xb7\xac\xe0\x60\x2bG\xba\x91\xcbu\x8e\x233\xc4\xe3...
    } else {            # decipher
        $$dataPt =~ tr/\x08\x1b\x40\x7d\xd8\x5e\x0e\xe7\x04V\xea\xcd\x05\x8ap\xb6i\x88\x200\xbe\xd7\x81\xbb\x92\x0c\x28\xecl\xa0\x95Q\xd3\x2f\x5dj\x5c9\x07\xc5\x87L\x1a\xf0\xe2\xef\x24y\x02\xb7\xac\xe0\x60\x2bG\xba\x91\xcbu\x8e\x233\xc4\xe3\x96\xdc\x...
    }
}

#------------------------------------------------------------------------------
# Process Sony 0x94xx cipherdata directory
# Inputs: 0) ExifTool object ref, 1) directory information ref, 2) tag table ref
# Returns: 1 on success
# Notes:
# 1) dirInfo may contain VarFormatData (reference to empty list) to return
#    details about any variable-length-format tags in the table (used when writing)
# 2) A bug in ExifTool 9.04-9.10 could have double-enciphered these blocks
sub ProcessEnciphered($$$)
{
    my ($et, $dirInfo, $tagTablePtr) = @_;
    my $dataPt = $$dirInfo{DataPt};
    my $dirStart = $$dirInfo{DirStart} || 0;
    my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $dirStart);
    my $data = substr($$dataPt, $dirStart, $dirLen);
    my %dirInfo = (
        %$dirInfo,
        DataPt => \$data,
        DataPos => $$dirInfo{DataPos} + $dirStart,
        DirStart => 0,
    );
    Decipher(\$data);
    if ($$et{DoubleCipher}) {
        Decipher(\$data);
        $et->Warn('Some Sony metadata is double-enciphered. Write any tag to fix',1);
    }
    if ($et->Options('Verbose') > 2) {
        my $tagInfo = $$dirInfo{TagInfo} || { Name => 'data' };
        my $str = $$et{DoubleCipher} ? 'ouble-d' : '';
        $et->VerboseDir("D${str}eciphered $$tagInfo{Name}");
        $et->VerboseDump(\$data,
            Prefix  => $$et{INDENT} . '  ',
            DataPos => $$dirInfo{DirStart} + $$dirInfo{DataPos} + ($$dirInfo{Base} || 0),
        );
    }
    return $et->ProcessBinaryData(\%dirInfo, $tagTablePtr);
}

#------------------------------------------------------------------------------
# Write Sony 0x94xx cipherdata directory
# Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
# Returns: cipherdata block or undefined on error
sub WriteEnciphered($$$)
{
    my ($et, $dirInfo, $tagTablePtr) = @_;
    $et or return 1;
    my $dataPt = $$dirInfo{DataPt};
    my $dirStart = $$dirInfo{DirStart} || 0;
    my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $dirStart);
    my $data = substr($$dataPt, $dirStart, $dirLen);
    my $changed = $$et{CHANGED};



( run in 0.398 second using v1.01-cache-2.11-cpan-39bf76dae61 )