518 lines
16 KiB
Perl
518 lines
16 KiB
Perl
#------------------------------------------------------------------------------
|
|
# File: Leaf.pm
|
|
#
|
|
# Description: Read Creo Leaf EXIF meta information
|
|
#
|
|
# Revisions: 09/28/2005 - P. Harvey Created
|
|
#------------------------------------------------------------------------------
|
|
|
|
package Image::ExifTool::Leaf;
|
|
|
|
use strict;
|
|
use vars qw($VERSION);
|
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
use Image::ExifTool::Exif;
|
|
|
|
$VERSION = '1.07';
|
|
|
|
sub ProcessLeaf($$$);
|
|
|
|
%Image::ExifTool::Leaf::Main = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Camera' },
|
|
NOTES => q{
|
|
These tags are found in .MOS images from Leaf digital camera backs as
|
|
written by Creo Leaf Capture. They exist within the Leaf-specific directory
|
|
structure of EXIF tag 0x8606. The tables below list observed Leaf tags,
|
|
however ExifTool will extract any tags found in the Leaf directories even if
|
|
they don't appear in these tables.
|
|
},
|
|
icc_camera_profile => {
|
|
Name => 'ICC_Profile',
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::ICC_Profile::Main',
|
|
},
|
|
},
|
|
icc_rgb_ws_profile => {
|
|
Name => 'RGB_Profile',
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::ICC_Profile::Main',
|
|
},
|
|
},
|
|
camera_profile => {
|
|
Name => 'CameraProfile',
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::CameraProfile',
|
|
},
|
|
},
|
|
JPEG_preview_data => {
|
|
%Image::ExifTool::previewImageTagInfo,
|
|
Groups => { 2 => 'Preview' },
|
|
},
|
|
JPEG_preview_info => 'PreviewInfo',
|
|
icc_camera_to_tone_space_flow => {
|
|
Name => 'ToneSpaceFlow',
|
|
Description => 'ICC To Tone Space Flow',
|
|
Format => 'int16u',
|
|
},
|
|
icc_camera_to_tone_matrix => {
|
|
Name => 'ToneMatrix',
|
|
Description => 'ICC To Tone Matrix',
|
|
Format => 'int8u',
|
|
Binary => 1,
|
|
},
|
|
PDA_histogram_data => {
|
|
Name => 'PDAHistogram',
|
|
Binary => 1,
|
|
},
|
|
pattern_ratation_angle => {
|
|
Name => 'PatternAngle',
|
|
Description => 'Pattern Rotation Angle',
|
|
Format => 'int16u',
|
|
Notes => '"ratation" is not a typo',
|
|
},
|
|
back_serial_number => {
|
|
Name => 'BackSerial',
|
|
Description => 'Back Serial Number',
|
|
PrintConv => '$val =~ s/ .*//s; $val',
|
|
},
|
|
image_offset => { Format => 'int16u' },
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::CameraProfile = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Camera' },
|
|
CamProf_version => 'CameraProfileVersion',
|
|
CamProf_name => 'CameraName',
|
|
CamProf_type => 'CameraType',
|
|
CamProf_back_type => 'CameraBackType',
|
|
CamProf_back_type => {
|
|
Name => 'CameraBackType',
|
|
},
|
|
CamProf_capture_profile => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::CaptureProfile',
|
|
},
|
|
},
|
|
CamProf_image_profile => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::ImageProfile',
|
|
},
|
|
},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::CaptureProfile = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Image' },
|
|
CaptProf_version => {},
|
|
CaptProf_name => {},
|
|
CaptProf_type => {},
|
|
CaptProf_back_type => {},
|
|
CaptProf_serial_number => {
|
|
Name => 'CaptureSerial',
|
|
Description => 'Capture Serial Number',
|
|
PrintConv => '$val =~ s/ .*//s; $val',
|
|
},
|
|
CaptProf_image_offset => {},
|
|
CaptProf_luminance_consts => {},
|
|
CaptProf_xy_offset_info => 'XYOffsetInfo',
|
|
CaptProf_color_matrix => {},
|
|
CaptProf_reconstruction_type=> {},
|
|
CaptProf_image_fields => {},
|
|
CaptProf_image_bounds => {},
|
|
CaptProf_number_of_planes => {},
|
|
CaptProf_raw_data_rotation => {},
|
|
CaptProf_color_averages => {},
|
|
CaptProf_mosaic_pattern => {},
|
|
CaptProf_dark_correction_type=>{},
|
|
CaptProf_right_dark_rect => {},
|
|
CaptProf_left_dark_rect => {},
|
|
CaptProf_center_dark_rect => {},
|
|
CaptProf_CCD_rect => {},
|
|
CaptProf_CCD_valid_rect => {},
|
|
CaptProf_CCD_video_rect => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::ImageProfile = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Image' },
|
|
ImgProf_version => {},
|
|
ImgProf_name => {},
|
|
ImgProf_type => {},
|
|
ImgProf_back_type => {},
|
|
ImgProf_shoot_setup => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::ShootSetup',
|
|
},
|
|
},
|
|
ImgProf_image_status => {},
|
|
ImgProf_rotation_angle => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::ShootSetup = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Image' },
|
|
ShootObj_version => {},
|
|
ShootObj_name => {},
|
|
ShootObj_type => {},
|
|
ShootObj_back_type => {},
|
|
ShootObj_capture_setup => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::CaptureSetup',
|
|
},
|
|
},
|
|
ShootObj_color_setup => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::ColorSetup',
|
|
},
|
|
},
|
|
ShootObj_save_setup => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::SaveSetup',
|
|
},
|
|
},
|
|
ShootObj_camera_setup => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::CameraSetup',
|
|
},
|
|
},
|
|
ShootObj_look_header => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::LookHeader',
|
|
},
|
|
},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::CaptureSetup = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Image' },
|
|
CaptureObj_version => {},
|
|
CaptureObj_name => {},
|
|
CaptureObj_type => {},
|
|
CaptureObj_back_type => {},
|
|
CaptureObj_neutals => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::Neutrals',
|
|
},
|
|
},
|
|
CaptureObj_selection => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::Selection',
|
|
},
|
|
},
|
|
CaptureObj_tone_curve => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::ToneCurve',
|
|
},
|
|
},
|
|
CaptureObj_sharpness => {
|
|
SubDirectory => {
|
|
TagTable => 'Image::ExifTool::Leaf::Sharpness',
|
|
},
|
|
},
|
|
CaptureObj_single_quality => {},
|
|
CaptureObj_Multi_quality => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::Neutrals = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Image' },
|
|
NeutObj_version => {},
|
|
NeutObj_name => {},
|
|
NeutObj_type => {},
|
|
NeutObj_back_type => {},
|
|
NeutObj_neutrals => {},
|
|
NeutObj_color_casts => {},
|
|
NeutObj_shadow_end_points => {},
|
|
NeutObj_highlight_end_points => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::Selection = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Image' },
|
|
SelObj_version => {},
|
|
SelObj_name => {},
|
|
SelObj_type => {},
|
|
SelObj_back_type => {},
|
|
SelObj_rect => {},
|
|
SelObj_resolution => {},
|
|
SelObj_scale => {},
|
|
SelObj_locks => {},
|
|
SelObj_orientation => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::ToneCurve = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Image' },
|
|
ToneObj_version => {},
|
|
ToneObj_name => {},
|
|
ToneObj_type => {},
|
|
ToneObj_back_type => {},
|
|
ToneObj_npts => {},
|
|
ToneObj_tones => {},
|
|
ToneObj_gamma => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::Sharpness = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Image' },
|
|
SharpObj_version => {},
|
|
SharpObj_name => {},
|
|
SharpObj_type => {},
|
|
SharpObj_back_type => {},
|
|
SharpObj_sharp_method => {},
|
|
SharpObj_data_len => {},
|
|
SharpObj_sharp_info => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::ColorSetup = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Image' },
|
|
ColorObj_version => {},
|
|
ColorObj_name => {},
|
|
ColorObj_type => {},
|
|
ColorObj_back_type => {},
|
|
ColorObj_has_ICC => {},
|
|
ColorObj_input_profile => {},
|
|
ColorObj_output_profile => {},
|
|
ColorObj_color_mode => {},
|
|
ColorObj_color_type => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::SaveSetup = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Other' },
|
|
SaveObj_version => {},
|
|
SaveObj_name => {},
|
|
SaveObj_type => {},
|
|
SaveObj_back_type => {},
|
|
SaveObj_leaf_auto_active=> {},
|
|
SaveObj_leaf_hot_folder => {},
|
|
SaveObj_leaf_output_file_type => {},
|
|
SaveObj_leaf_auto_base_name => {},
|
|
SaveObj_leaf_save_selection => {},
|
|
SaveObj_leaf_open_proc_HDR => {},
|
|
SaveObj_std_auto_active => {},
|
|
SaveObj_std_hot_folder => {},
|
|
SaveObj_std_output_file_type => {},
|
|
SaveObj_std_output_color_mode => {},
|
|
SaveObj_std_output_bit_depth => {},
|
|
SaveObj_std_base_name => {},
|
|
SaveObj_std_save_selection => {},
|
|
SaveObj_std_oxygen => {},
|
|
SaveObj_std_open_in_photoshop => {},
|
|
SaveObj_std_scaled_output => {},
|
|
SaveObj_std_sharpen_output => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::CameraSetup = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Camera' },
|
|
CameraObj_version => {},
|
|
CameraObj_name => {},
|
|
CameraObj_type => {},
|
|
CameraObj_back_type => {},
|
|
CameraObj_ISO_speed => {},
|
|
CameraObj_strobe => {},
|
|
CameraObj_camera_type => {},
|
|
CameraObj_lens_type => {},
|
|
CameraObj_lens_ID => {},
|
|
);
|
|
|
|
%Image::ExifTool::Leaf::LookHeader = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Other' },
|
|
LookHead_version => {},
|
|
LookHead_name => {},
|
|
LookHead_type => {},
|
|
LookHead_back_type => {},
|
|
);
|
|
|
|
# tag table for any unknown Leaf directories
|
|
%Image::ExifTool::Leaf::Unknown = (
|
|
PROCESS_PROC => \&ProcessLeaf,
|
|
GROUPS => { 0 => 'Leaf', 2 => 'Unknown' },
|
|
);
|
|
|
|
# table for Leaf SubIFD entries
|
|
%Image::ExifTool::Leaf::SubIFD = (
|
|
GROUPS => { 0 => 'MakerNotes', 1 => 'LeafSubIFD', 2 => 'Image'},
|
|
WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
|
|
NOTES => q{
|
|
Leaf writes a TIFF-format sub-IFD inside IFD0 of a MOS image. No tags in
|
|
this sub-IFD are currently known, except for tags 0x8602 and 0x8606 which
|
|
really shouldn't be here anyway (so they don't appear in the table below)
|
|
because they duplicate references to the same data from tags with the same
|
|
ID in IFD0.
|
|
},
|
|
);
|
|
|
|
# prepare Leaf tables by generating tag 'Name' and table 'NOTES'
|
|
{
|
|
my @tableList = ( 'Image::ExifTool::Leaf::Main' );
|
|
my ($tag, %doneTable);
|
|
# keep prefix in tag name of common tags
|
|
my %keepPrefix = ( Version=>1, Name=>1, Type=>1, BackType=>1 );
|
|
while (@tableList) {
|
|
my $table = shift @tableList;
|
|
next if $doneTable{$table};
|
|
my $prefix = ($table =~ /::Main$/) ? undef : '';
|
|
$doneTable{$table} = 1;
|
|
no strict 'refs';
|
|
$table = \%$table;
|
|
use strict 'refs';
|
|
foreach $tag (keys %$table) {
|
|
my $tagInfo = $$table{$tag};
|
|
next unless ref $tagInfo eq 'HASH';
|
|
next if $tag eq 'GROUPS';
|
|
if (defined $prefix and not $prefix) {
|
|
($prefix = $tag) =~ s/_.*//;
|
|
}
|
|
unless ($$tagInfo{Name}) {
|
|
my $name;
|
|
($name = $tag) =~ s/_(.)/\U$1/g;
|
|
if ($prefix) {
|
|
$name =~ s/^$prefix//;
|
|
$name = $prefix . $name if $keepPrefix{$name};
|
|
}
|
|
$$tagInfo{Name} = ucfirst($name);
|
|
}
|
|
next unless $$tagInfo{SubDirectory};
|
|
my $subTable = $tagInfo->{SubDirectory}->{TagTable};
|
|
next unless $subTable =~ /::Leaf::/;
|
|
push @tableList, $subTable;
|
|
}
|
|
next unless $prefix;
|
|
$$table{NOTES} = "All B<Tag ID>'s in the following table have a " .
|
|
"leading '${prefix}_' which\nhas been removed.\n";
|
|
}
|
|
}
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Process Leaf information
|
|
# Inputs: 0) ExifTool object reference
|
|
# 1) Reference to directory information hash
|
|
# 2) Pointer to tag table for this directory
|
|
# Returns: 1 on success, otherwise returns 0 and sets a Warning
|
|
sub ProcessLeaf($$$)
|
|
{
|
|
my ($et, $dirInfo, $tagTablePtr) = @_;
|
|
my $dataPt = $$dirInfo{DataPt};
|
|
my $dirStart = $$dirInfo{DirStart} || 0;
|
|
my $dirLen = $$dirInfo{DirLen} || $$dirInfo{DataLen} - $dirStart;
|
|
my $dirEnd = $dirStart + $dirLen;
|
|
my $verbose = $et->Options('Verbose');
|
|
my $pos = $dirStart;
|
|
my $hdrLen = 52; # header length for PKTS information
|
|
my $success;
|
|
|
|
$verbose and $et->VerboseDir('Leaf');
|
|
for (;;) {
|
|
last if $pos + $hdrLen > $dirEnd;
|
|
my $header = substr($$dataPt, $pos, $hdrLen);
|
|
last unless substr($header, 0, 4) eq 'PKTS';
|
|
$success = 1;
|
|
my $size = Get32u(\$header, 48);
|
|
$pos += $hdrLen;
|
|
if ($pos + $size > $dirEnd) {
|
|
$et->Warn('Truncated Leaf data');
|
|
last;
|
|
}
|
|
my $tag = substr($header, 8, 40);
|
|
$tag =~ s/\0.*//s;
|
|
next unless $tag;
|
|
my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
|
|
# generate tag info for unknown tags
|
|
my $val;
|
|
if ($tagInfo and $$tagInfo{Format}) {
|
|
$val = ReadValue($dataPt, $pos, $$tagInfo{Format}, undef, $size);
|
|
} else {
|
|
$val = substr($$dataPt, $pos, $size);
|
|
}
|
|
unless ($tagInfo) {
|
|
my $name = ucfirst($tag);
|
|
$name =~ s/_(.)/\U$1/g;
|
|
if ($val =~ /^PKTS\0\0\0\x01/) {
|
|
# also unpack unknown directories
|
|
$tagInfo = {
|
|
Name => $name,
|
|
SubDirectory => { TagTable => 'Image::ExifTool::Leaf::Unknown' },
|
|
};
|
|
} elsif ($tagTablePtr ne \%Image::ExifTool::Leaf::Main or
|
|
$et->Options('Unknown'))
|
|
{
|
|
$tagInfo = {
|
|
Name => $name,
|
|
Writable => 0,
|
|
PrintConv => 'length($val) > 60 ? substr($val,0,55) . "[...]" : $val',
|
|
};
|
|
# make tags in main table unknown because they tend to be binary
|
|
$$tagInfo{Unknown} = 1 if $tagTablePtr eq \%Image::ExifTool::Leaf::Main;
|
|
}
|
|
$tagInfo and AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
|
}
|
|
if ($verbose) {
|
|
$et->VerboseInfo($tag, $tagInfo,
|
|
Table => $tagTablePtr,
|
|
Value => $val,
|
|
DataPt => $dataPt,
|
|
DataPos => $$dirInfo{DataPos},
|
|
Size => $size,
|
|
Start => $pos,
|
|
);
|
|
}
|
|
if ($tagInfo) {
|
|
if ($$tagInfo{SubDirectory}) {
|
|
my %subdirInfo = (
|
|
DataPt => $dataPt,
|
|
DirLen => $size,
|
|
DirStart => $pos,
|
|
DataPos => $$dirInfo{DataPos},
|
|
DirName => 'Leaf PKTS',
|
|
);
|
|
my $subTable = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
|
|
$et->ProcessDirectory(\%subdirInfo, $subTable);
|
|
} else {
|
|
$val =~ tr/\n/ /; # translate newlines to spaces
|
|
$val =~ s/\0+$//; # remove null terminators
|
|
$et->FoundTag($tagInfo, $val);
|
|
}
|
|
}
|
|
$pos += $size;
|
|
}
|
|
$success or $et->Warn('Bad format Leaf data');
|
|
return $success;
|
|
}
|
|
|
|
1; # end
|
|
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
Image::ExifTool::Leaf - Read Creo Leaf EXIF 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 interpret
|
|
meta information from Leaf digital camera backs written by Creo Leaf
|
|
Capture.
|
|
|
|
=head1 AUTHOR
|
|
|
|
Copyright 2003-2018, 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 SEE ALSO
|
|
|
|
L<Image::ExifTool::TagNames/Leaf Tags>,
|
|
L<Image::ExifTool(3pm)|Image::ExifTool>
|
|
|
|
=cut
|