This commit is contained in:
Xes
2025-08-14 22:41:49 +02:00
parent 2de81ccc46
commit 8ce45119b6
39774 changed files with 4309466 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
#------------------------------------------------------------------------------
# File: convert_regions.config
#
# Description: User-defined Composite tag definitions to allow conversion of
# face regions between Microsoft Windows Live Photo Gallery (WLPG)
# and Metadata Working Group (MWG) formats
#
# Usage: 1) Convert from MP WLPG regions to MWG regions:
#
# exiftool -config convert_regions.config "-regioninfo<myregion" FILE
#
# 2) Convert from MWG to WLPG regions:
#
# exiftool -config convert_regions.config "-regioninfomp<myregionmp" FILE
#
# Requires: ExifTool version 8.82 or later
#
# Revisions: 2012/12/27 - P. Harvey Created
# 2013/02/20 - PH Don't add ignored MP faces
#
# References: http://www.metadataworkinggroup.org/specs/
#------------------------------------------------------------------------------
%Image::ExifTool::UserDefined = (
'Image::ExifTool::Composite' => {
# create an MWG RegionInfo structure from a Microsoft RegionInfoMP structure
MyRegion => {
Require => {
0 => 'RegionInfoMP',
1 => 'ImageWidth',
2 => 'ImageHeight',
},
ValueConv => q{
my ($rgn, @newRgns);
foreach $rgn (@{$val[0]{Regions}}) {
# don't add ignored faces
next if $$rgn{PersonDisplayName} eq 'ffffffffffffffff';
my @rect = split /\s*,\s*/, $$rgn{Rectangle};
my %newRgn = (
Area => {
X => $rect[0] + $rect[2]/2,
Y => $rect[1] + $rect[3]/2,
W => $rect[2],
H => $rect[3],
Unit => 'normalized',
},
Name => $$rgn{PersonDisplayName},
Type => 'Face',
);
push @newRgns, \%newRgn;
}
return {
AppliedToDimensions => { W => $val[1], H => $val[2], Unit => 'pixel' },
RegionList => \@newRgns,
};
},
},
# create a Microsoft RegionInfoMP structure from an MWG RegionInfo structure
MyRegionMP => {
Require => 'RegionInfo',
ValueConv => q{
my ($rgn, @newRgns);
foreach $rgn (@{$val[0]{RegionList}}) {
my @rect = @{$$rgn{Area}}{'X','Y','W','H'};
$rect[0] -= $rect[2]/2;
$rect[1] -= $rect[3]/2;
push @newRgns, {
PersonDisplayName => $$rgn{Name},
Rectangle => join(', ', @rect),
};
}
return { Regions => \@newRgns };
},
},
},
);
1; #end

View File

@@ -0,0 +1,343 @@
#------------------------------------------------------------------------------
# File: ExifTool_config --> ~/.ExifTool_config
#
# Description: Sample user configuration file for Image::ExifTool
#
# Notes: This example file shows how to define your own shortcuts and
# add new EXIF, IPTC, XMP, PNG, MIE and Composite tags, as well
# as how to specify preferred lenses for the LensID tag, and
# define new file types and default ExifTool option values.
#
# Note that unknown tags may be extracted even if they aren't
# defined, but tags must be defined to be written. Also note
# that it is possible to override an existing tag definition
# with a user-defined tag.
#
# To activate this file, rename it to ".ExifTool_config" and
# place it in your home directory or the exiftool application
# directory. (On Windows and Mac systems this must be done via
# the command line since the GUI's don't allow filenames to begin
# with a dot. Use the "rename" command in Windows or "mv" on the
# Mac.) This causes ExifTool to automatically load the file when
# run. Your home directory is determined by the first defined of
# the following environment variables:
#
# 1. EXIFTOOL_HOME
# 2. HOME
# 3. HOMEDRIVE + HOMEPATH
# 4. (the current directory)
#
# Alternatively, the -config option of the exiftool application
# may be used to load a specific configuration file (note that
# this must be the first option on the command line):
#
# exiftool -config example.config ...
#
# This example file defines the following 16 new tags as well as
# a number of Shortcut and Composite tags:
#
# 1. EXIF:NewEXIFTag
# 2. GPS:GPSPitch
# 3. GPS:GPSRoll
# 4. IPTC:NewIPTCTag
# 5. XMP-xmp:NewXMPxmpTag
# 6. XMP-exif:GPSPitch
# 7. XMP-exif:GPSRoll
# 8. XMP-xxx:NewXMPxxxTag1
# 9. XMP-xxx:NewXMPxxxTag2
# 10. XMP-xxx:NewXMPxxxTag3
# 11. XMP-xxx:NewXMPxxxStruct
# 12. PNG:NewPngTag1
# 13. PNG:NewPngTag2
# 14. PNG:NewPngTag3
# 15. MIE-Meta:NewMieTag1
# 16. MIE-Test:NewMieTag2
#
# For detailed information on the definition of tag tables and
# tag information hashes, see lib/Image/ExifTool/README.
#------------------------------------------------------------------------------
# Shortcut tags are used when extracting information to simplify
# commonly used commands. They can be used to represent groups
# of tags, or to provide an alias for a tag name.
%Image::ExifTool::UserDefined::Shortcuts = (
MyShortcut => ['exif:createdate','exposuretime','aperture'],
MyAlias => 'FocalLengthIn35mmFormat',
);
# NOTE: All tag names used in the following tables are case sensitive.
# The %Image::ExifTool::UserDefined hash defines new tags to be added
# to existing tables.
%Image::ExifTool::UserDefined = (
# All EXIF tags are added to the Main table, and WriteGroup is used to
# specify where the tag is written (default is ExifIFD if not specified):
'Image::ExifTool::Exif::Main' => {
# Example 1. EXIF:NewEXIFTag
0xd000 => {
Name => 'NewEXIFTag',
Writable => 'int16u',
WriteGroup => 'IFD0',
},
# add more user-defined EXIF tags here...
},
# the Geotag feature writes these additional GPS tags if available:
'Image::ExifTool::GPS::Main' => {
# Example 2. GPS:GPSPitch
0xd000 => {
Name => 'GPSPitch',
Writable => 'rational64s',
},
# Example 3. GPS:GPSRoll
0xd001 => {
Name => 'GPSRoll',
Writable => 'rational64s',
},
},
# IPTC tags are added to a specific record type (eg. application record):
# (Note: IPTC tag ID's are limited to the range 0-255)
'Image::ExifTool::IPTC::ApplicationRecord' => {
# Example 4. IPTC:NewIPTCTag
160 => {
Name => 'NewIPTCTag',
Format => 'string[0,16]',
},
# add more user-defined IPTC ApplicationRecord tags here...
},
# XMP tags may be added to existing namespaces:
'Image::ExifTool::XMP::xmp' => {
# Example 5. XMP-xmp:NewXMPxmpTag
NewXMPxmpTag => { Groups => { 2 => 'Author' } },
# add more user-defined XMP-xmp tags here...
},
# special Geotag tags for XMP-exif:
'Image::ExifTool::XMP::exif' => {
# Example 6. XMP-exif:GPSPitch
GPSPitch => { Writable => 'rational', Groups => { 2 => 'Location' } },
# Example 7. XMP-exif:GPSRoll
GPSRoll => { Writable => 'rational', Groups => { 2 => 'Location' } },
},
# new XMP namespaces (eg. xxx) must be added to the Main XMP table:
'Image::ExifTool::XMP::Main' => {
# namespace definition for examples 8 to 11
xxx => { # <-- must be the same as the NAMESPACE prefix
SubDirectory => {
TagTable => 'Image::ExifTool::UserDefined::xxx',
# (see the definition of this table below)
},
},
# add more user-defined XMP namespaces here...
},
# new PNG tags are added to the PNG::TextualData table:
'Image::ExifTool::PNG::TextualData' => {
# Example 12. PNG:NewPngTag1
NewPngTag1 => { },
# Example 13. PNG:NewPngTag2
NewPngTag2 => { },
# Example 14. PNG:NewPngTag3
NewPngTag3 => { },
},
# add a new MIE tag (NewMieTag1) and group (MIE-Test) to MIE-Meta
# (Note: MIE group names must NOT end with a number)
'Image::ExifTool::MIE::Meta' => {
# Example 15. MIE-Meta:NewMieTag1
NewMieTag1 => {
Writable => 'rational64u',
Units => [ 'cm', 'in' ],
},
# new MIE "Test" group for example 16
Test => {
SubDirectory => {
TagTable => 'Image::ExifTool::UserDefined::MIETest',
DirName => 'MIE-Test',
},
},
},
# Composite tags are added to the Composite table:
'Image::ExifTool::Composite' => {
# Composite tags are unique: The Require/Desire elements specify
# tags that must/may exist, and the keys of these hashes are used as
# indices in the @val array of the ValueConv expression to access
# the numerical (-n) values of these tags. All Require'd tags must
# exist for the Composite tag to be evaluated. If no Require'd tags
# are specified, then at least one of the Desire'd tags must exist.
# See the Composite table in Image::ExifTool::Exif for more examples,
# and lib/Image/ExifTool/README for all of the details.
BaseName => {
Require => {
0 => 'FileName',
},
# remove the extension from FileName
ValueConv => '$val[0] =~ /(.*)\./ ? $1 : $val[0]',
},
# the next few examples demonstrate simplifications which may be
# used if only one tag is Require'd or Desire'd:
# 1) the Require lookup may be replaced with a simple tag name
# 2) "$val" may be used to represent "$val[0]" in the expression
FileExtension => {
Require => 'FileName',
ValueConv => '$val=~/\.([^.]*)$/; $1',
},
# override CircleOfConfusion tag to use D/1750 instead of D/1440
CircleOfConfusion => {
Require => 'ScaleFactor35efl',
Groups => { 2 => 'Camera' },
ValueConv => 'sqrt(24*24+36*36) / ($val * 1750)',
# an optional PrintConv may be used to format the value
PrintConv => 'sprintf("%.3f mm",$val)',
},
# generate a description for this file type
FileTypeDescription => {
Require => 'FileType',
ValueConv => 'GetFileType($val,1) || $val',
},
# calculate physical image size based on resolution
PhysicalImageSize => {
Require => {
0 => 'ImageWidth',
1 => 'ImageHeight',
2 => 'XResolution',
3 => 'YResolution',
4 => 'ResolutionUnit',
},
ValueConv => '$val[0]/$val[2] . " " . $val[1]/$val[3]',
# (the @prt array contains print-formatted values)
PrintConv => 'sprintf("%.1fx%.1f $prt[4]", split(" ",$val))',
},
# [advanced] select largest JPEG preview image
BigImage => {
Groups => { 2 => 'Preview' },
Desire => {
0 => 'JpgFromRaw',
1 => 'PreviewImage',
2 => 'OtherImage',
# (DNG and A100 ARW may be have 2 PreviewImage's)
3 => 'PreviewImage (1)',
},
# ValueConv may also be a code reference
# Inputs: 0) reference to list of values, 1) ExifTool object
ValueConv => sub {
my $val = shift;
my ($image, $bigImage, $len, $bigLen);
foreach $image (@$val) {
next unless ref $image eq 'SCALAR';
# check for JPEG image (or "Binary data" if -b not used)
next unless $$image =~ /^(\xff\xd8\xff|Binary data (\d+))/;
$len = $2 || length $$image; # get image length
# save largest image
next if defined $bigLen and $bigLen >= $len;
$bigLen = $len;
$bigImage = $image;
}
return $bigImage;
},
},
# **** ADD ADDITIONAL COMPOSITE TAG DEFINITIONS HERE ****
},
);
# This is a basic example of the definition for a new XMP namespace.
# This table is referenced through a SubDirectory tag definition
# in the %Image::ExifTool::UserDefined definition above.
# The namespace prefix for these tags is 'xxx', which corresponds to
# an ExifTool family 1 group name of 'XMP-xxx'.
%Image::ExifTool::UserDefined::xxx = (
GROUPS => { 0 => 'XMP', 1 => 'XMP-xxx', 2 => 'Image' },
NAMESPACE => { 'xxx' => 'http://ns.myname.com/xxx/1.0/' },
WRITABLE => 'string',
# Example 8. XMP-xxx:NewXMPxxxTag1
# - replace "NewXMPxxxTag1" with your own tag name (eg. "MyTag")
NewXMPxxxTag1 => { Writable => 'lang-alt' },
# Example 9. XMP-xxx:NewXMPxxxTag2
NewXMPxxxTag2 => { Groups => { 2 => 'Author' } },
# Example 10. XMP-xxx:NewXMPxxxTag3
NewXMPxxxTag3 => { List => 'Bag' },
# Example 11. XMP-xxx:NewXMPxxxStruct
# - example structured XMP tag
NewXMPxxxStruct => {
# the "Struct" entry defines the structure fields
Struct => {
# optional namespace prefix and URI for structure fields
# (required only if different than NAMESPACE above)
NAMESPACE => { 'test' => 'http://x.y.z/test/' },
# optional structure name (used for warning messages only)
STRUCT_NAME => 'MyStruct',
# optional rdf:type property for the structure
TYPE => 'http://x.y.z/test/xystruct',
# structure field definitions (very similar to tag definitions)
X => { Writable => 'integer' },
Y => { Writable => 'integer' },
# a nested structure...
Things => {
List => 'Bag',
Struct => {
NAMESPACE => { thing => 'http://x.y.z/thing/' },
What => { },
Where => { },
},
},
},
List => 'Seq', # structures may also be elements of a list
},
# Each field in the structure has an automatically-generated
# corresponding flattened tag with an ID that is the concatenation
# of the original structure tag ID and the field name (after
# capitalizing the first letter of the field name if necessary).
# The Name and/or Description of these flattened tags may be changed
# if desired, but all other tag properties are taken from the
# structure field definition. When this is done, the "Flat" flag
# must also be set in the tag definition. For example:
NewXMPxxxStructX => { Name => 'SomeOtherName', Flat => 1 },
);
# Adding a new MIE group requires a few extra definitions
use Image::ExifTool::MIE;
%Image::ExifTool::UserDefined::MIETest = (
%Image::ExifTool::MIE::tableDefaults, # default MIE table entries
GROUPS => { 0 => 'MIE', 1 => 'MIE-Test', 2 => 'Document' },
WRITE_GROUP => 'MIE-Test',
# Example 16. MIE-Test:NewMieTag2
NewMieTag2 => { }, # new user-defined tag in MIE-Test group
);
# A special 'Lenses' list can be defined to give priority to specific lenses
# in the logic to determine a lens model for the Composite:LensID tag
@Image::ExifTool::UserDefined::Lenses = (
'Sigma AF 10-20mm F4-5.6 EX DC',
'Tokina AF193-2 19-35mm f/3.5-4.5',
);
# User-defined file types to recognize
%Image::ExifTool::UserDefined::FileTypes = (
XXX => { # <-- the extension of the new file type (case insensitive)
# BaseType specifies the format upon which this file is based.
# If BaseType is defined, then the file will be fully supported,
# and in this case the Magic pattern should not be defined
BaseType => 'TIFF',
MIMEType => 'image/x-xxx',
Description => 'My XXX file type',
},
YYY => {
# without BaseType, the file will be recognized but not supported
Magic => '0123abcd', # regular expression to match at start of file
MIMEType => 'application/test',
Description => 'My YYY file type',
},
ZZZ => {
# if neither BaseType nor Magic are defined, the file will be
# recognized by extension only
Descripton => 'My ZZZ file type',
},
);
# Specify default ExifTool option values
# (see the Options function documentation for available options)
%Image::ExifTool::UserDefined::Options = (
CoordFormat => '%.6f', # change default GPS coordinate format
Duplicates => 1, # make -a default for the exiftool app
GeoMaxHDOP => 4, # ignore GPS fixes with HDOP > 4
SystemTags => 1, # extract additional File System tags
);
#------------------------------------------------------------------------------
1; #end

View File

@@ -0,0 +1,54 @@
#------------------------------------------------------------------------------
# File: photoshop_paths.config
#
# Description: This config file generates user-defined tags for Photoshop
# paths, and may be used to extract path names or copy path
# information from one file to another.
#
# An "AllPaths" shortcut tag is also provided represent all
# Photoshop path tags. This shortcut must be used when copying
# because these tags are marked as "Protected" so they won't be
# copied by default.
#
# Note: Print conversion must be disabled to be able to copy these tags
# (via either the -n option, or by adding a "#" to the tag name,
# eg. "-tagsfromfile SRC -allpaths#").
#
# Usage:
#
# 1) Extract Photoshop path names:
#
# exiftool -config photoshop_paths.config -allpaths FILE
#
# 2) Copy all Photoshop paths from one file (SRC) to another (DST):
#
# exiftool -config photoshop_paths.config -tagsfromfile SRC -allpaths# DST
#
# Requires: ExifTool version 9.95 or later
#
# Revisions: 2015/05/07 - P. Harvey Created
#
# References: http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,1621.0.html
# http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3910.0.html
#------------------------------------------------------------------------------
%Image::ExifTool::Shortcuts::UserDefined = (
# create "AllPaths" shortcut for all Photoshop path tags
AllPaths => [
map { sprintf "Path%x", $_ } (0x7d0 .. 0xbb5),
],
);
%Image::ExifTool::UserDefined = (
'Image::ExifTool::Photoshop::Main' => {
# generate tags for each of the 998 possible Photoshop paths
map { $_ => {
Name => sprintf('Path%x', $_),
Description => sprintf('Path %x', $_),
Flags => [ qw(Writable Protected Binary ConvertBinary SetResourceName) ],
PrintConv => '$$val =~ m{/#(.*?)#/$}s ? $1 : "<none>"',
} } (0x7d0 .. 0xbb5),
},
);
1; #end

View File

@@ -0,0 +1,371 @@
#------------------------------------------------------------------------------
# File: picasa_faces.config
#
# Description: User-defined Composite tag definitions to convert face regions
# in .picasa.ini files to MWG region tags (Metadata Working Group
# region, used by Picasa) and MP region tags (used by Microsoft
# Photo Library).
#
# Tag definitions and examples:
#
# PicasaToMWGRegion
# This will create the MWG region tag but will filter out the regions
# that are still unnamed in Picasa. Picasa defaults to naming these
# regions 'ffffffffffffffff' but normally will not save these to file.
# Example:
# exiftool -config picasa_faces.config "-RegionInfo<PicasaToMWGRegion" FILE
#
# PicasaToMPRegion
# This will create the MP region tag but will filter out the regions that
# are still unnamed in Picasa. Picasa defaults to naming these regions
# 'ffffffffffffffff' but normally will not save these to file.
# Example:
# exiftool -config picasa_faces.config "-RegionInfoMP<PicasaToMPRegion" FILE
#
# PicasaRegionNames
# Returns a list of the region names associated with the file. This
# allows copying of the region names to XMP:Subject and/or IPTC:Keywords.
# It also allows checking to see if regions need to be updated.
# Example:
# exiftool -config picasa_faces.config "-XMP:Subject<PicasaRegionNames" FILE
#
# PicasaToMWGRegionUnfiltered
# This will create the MWG region tag. This version does not filter out
# the unnamed regions. Picasa normally will filter out unnamed regions
# when it saves regions in the file.
# Example:
# exiftool -config picasa_faces.config "-RegionInfo<PicasaToMWGRegionUnfiltered" FILE
#
# PicasaToMPRegionUnfiltered
# This will create the MP region tag. This version does not filter out
# the unnamed regions. Picasa normally will filter out unnamed regions
# when it saves regions in the file.
# Example:
# exiftool -config picasa_faces.config "-RegionInfoMP<PicasaToMPRegionUnfiltered" FILE
#
# Notes: The face names are loaded from the Picasa contacts file, which
# defaults to:
#
# C:/Users/MainUser/AppData/Local/PicasaData/Google/Picasa2/contacts/contacts.xml
#
# The default contacts file may be changed by editing the value
# of $contactXML below, or on the command line with ExifTool 9.90
# or later via the -userParam option, eg:
# -userparam PicasaContactsFile=/path/to/contacts.xml
#
# Requires: ExifTool version 8.82 or later (9.90 or later for -userparam)
#
# Revisions: 2015/03/07 - Bryan K. Williams (aka StarGeek) Created
# 2015/03/12 - PH Minor changes, optimizations and reformatting
# 2015/05/11 - BKW Fix bug where Picasa writes region data for
# rotated NEF and CR2 images as if the orientation
# is not rotated.
# 2015/05/12 - PH Minor code tweaks
# 2015/10/26 - BKW Round off area sizes to 7 decimal places
# 2016/01/18 - BKW Improved rounding algorithm
#
# References: http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,6354.0.html
#------------------------------------------------------------------------------
# Picasa contacts file name
my $contactXML = 'C:/Users/MainUser/AppData/Local/PicasaData/Google/Picasa2/contacts/contacts.xml';
# local variables
my $lastIniFile = ''; # path of last .picasa.ini file loaded
my $lastContactFile = ''; # path of last contacts.xml file loaded
# raw file types that need additional processing to get regions correct
my %isRawFile = map { $_ => 1 } qw(
3FR ARW CR2 CRW CS1 DCR DNG EIP ERF IIQ K25 KDC MEF MOS MRW NEF NRW
ORF PEF RAF RAW RW2 RWL SR2 SRF SRW X3F), 'Canon 1D RAW';
my %contactHash; # lookup for loaded contacts.xml entries
my %fileHash; # lookup for loaded .picasa.ini entries
#------------------------------------------------------------------------------
# Load Picasa's contacts.xml and .picasa.ini files.
# Inputs: 0) ExifTool object reference, 1) .picasa.ini directory
# Returns: 1 if files were loaded and parsed, undef on error
# Notes: If file has already been loaded, it isn't reloaded
sub LoadPicasaFiles($$)
{
local (*CONTACTS, *INI);
my ($et, $iniDir) = @_;
# check ExifTool version to see if there might be
# a command line setting for the contact file
my $contactFile = ($Image::ExifTool::VERSION >= 9.89 and
defined($et->Options(UserParam => 'PicasaContactsFile'))) ?
$et->Options(UserParam => 'PicasaContactsFile') : $contactXML;
# load Picasa contacts.xml file unless done already
unless ($contactFile eq $lastContactFile) {
$lastContactFile = $contactFile;
undef %contactHash;
# Picasa's default setting for unnamed faces.
$contactHash{'ffffffffffffffff'} = 'unnamed';
if (open(CONTACTS, $contactFile)) {
require Image::ExifTool::HTML;
while (<CONTACTS>) {
/name="(.*?)"/ or next;
my $name = $1;
/id="([a-f0-9]+)"/ or next;
my $id = $1;
$contactHash{$id} = Image::ExifTool::HTML::UnescapeHTML($name);
}
close(CONTACTS);
} else {
local $SIG{'__WARN__'} = undef; # stop ExifTool from catching the warning
warn "Error reading contacts file $contactFile\n";
}
}
# load .picasa.ini file from the specified directory
my $iniFile = "$iniDir/.picasa.ini";
if ($iniFile eq $lastIniFile) {
return %fileHash ? 1 : undef;
}
$lastIniFile = $iniFile;
open(INI, $iniFile) or return undef;
my $section = '';
while (<INI>) {
# Process New Section
/^\s*\[(.+)\][\n\r]*$/ and $section = $1, next;
# process entry (all we care about are the "faces" lines)
/^faces=(.*)$/ or next;
my @temp = split /;/, $1;
foreach (@temp) {
/rect64\(([\da-f]{1,16})\),([\da-f]{1,16})/ or next;
# the string in parens after "rect64" is a 64 bit number in hex,
# but Picasa doesn't add leading zeroes, so the length of the string
# cannot be assumed to be 16 bytes. Handle this as two 32-bit numbers
# for compatibility with 32-bit systems.
my $hi = hex(substr($1, 0, -8));
my $lo = hex(substr($1, -8));
my $x0 = ($hi >> 16) /65535;
my $y0 = ($hi & 0xffff)/65535;
my $x1 = ($lo >> 16) /65535;
my $y1 = ($lo & 0xffff)/65535;
push @{ $fileHash{$section} }, {
ContactID => $2,
# round to 8 decimals (Picasa will ignore regions with greater than 10 decimals)
X => int($x0*100000000+.5)/100000000,
Y => int($y0*100000000+.5)/100000000,
W => int(($x1 - $x0)*100000000+.5)/100000000,
H => int(($y1 - $y0)*100000000+.5)/100000000,
};
}
}
close(INI);
return %fileHash ? 1 : undef;
}
#------------------------------------------------------------------------------
# Rotate region to specified orientation (for RAW file types only)
# Input: 0) rectangle array ref (x,y,w,h), 1) EXIF orientation value, 2) file type
sub RotateRegion($$$)
{
my ($rect, $orientation, $fileType) = @_;
if ($orientation and $fileType and $isRawFile{$fileType}) {
my ($x,$y,$w,$h) = @$rect;
if ($orientation == 8) { # CW 90
@$rect = (1-$h-$y, $x, $h, $w);
} elsif ($orientation == 3) { # CW 180
@$rect = (1-$x-$w, 1-$y-$h, $w, $h);
} elsif ($orientation == 6) { # CW 270
@$rect = ($y, 1-$x-$w, $h, $w);
}
}
}
#------------------------------------------------------------------------------
# User-defined tag definitions
#
%Image::ExifTool::UserDefined = (
'Image::ExifTool::Composite' => {
#
# Versions that filter out unnamed regions (ContactID=ffffffffffffffff)
#
PicasaToMWGRegion => {
Require => {
0 => 'Directory',
1 => 'FileName',
2 => 'ImageWidth',
3 => 'ImageHeight',
},
Desire => {
4 => 'Orientation',
5 => 'FileType',
},
ValueConv => sub {
my ($val, $et) = @_;
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
my $filename = $$val[1];
my @regList;
# convert to local variables for readability, and make
# sure there is a region associated with the current file
my $contactHashRef = \%contactHash;
my $tempArrayRef = $fileHash{$filename} or return undef;
foreach my $tempHash (@$tempArrayRef) {
next if $$tempHash{ContactID} eq 'ffffffffffffffff';
my $name = $$contactHashRef{$$tempHash{ContactID}};
next unless defined $name;
my @rect = @$tempHash{'X','Y','W','H'};
RotateRegion(\@rect, $$val[4], $$val[5]);
push @regList, {
Area => {
X => $rect[0] + $rect[2] / 2,
Y => $rect[1] + $rect[3] / 2,
W => $rect[2],
H => $rect[3],
Unit => 'normalized',
},
Name => $name,
Type => 'Face',
};
}
# make sure a region exists, otherwise return undef
return @regList ? {
AppliedToDimensions => { W => $$val[2], H => $$val[3], Unit => 'pixel' },
RegionList => \@regList,
} : undef;
},
},
PicasaToMPRegion => {
Require => {
0 => 'Directory',
1 => 'FileName',
},
Desire => {
2 => 'Orientation',
3 => 'FileType',
},
ValueConv => sub {
my ($val, $et) = @_;
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
my $filename = $$val[1];
my @regList;
# convert to local variables for readability, and make
# sure there is a region associated with the current file
my $contactHashRef = \%contactHash;
my $tempArrayRef = $fileHash{$filename} or return undef;
foreach my $tempHash (@$tempArrayRef) {
next if $$tempHash{ContactID} eq 'ffffffffffffffff';
my $name = $$contactHashRef{$$tempHash{ContactID}};
next unless defined $name;
my @rect = @$tempHash{'X','Y','W','H'};
RotateRegion(\@rect, $$val[2], $$val[3]);
push @regList, {
PersonDisplayName => $name,
Rectangle => join(', ', @rect),
};
}
# make sure a region exists, otherwise return undef
return @regList ? { Regions => \@regList } : undef;
},
},
PicasaRegionNames => {
Require => {
0 => 'Directory',
1 => 'FileName',
},
ValueConv => sub {
my ($val, $et) = @_;
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
my $filename = $$val[1];
my @regList;
# convert to local variables for readability, and make
# sure there is a region associated with the current file
my $contactHashRef = \%contactHash;
my $tempArrayRef = $fileHash{$filename} or return undef;
foreach my $tempHash (@$tempArrayRef) {
next if $$tempHash{ContactID} eq 'ffffffffffffffff';
my $name = $$contactHashRef{$$tempHash{ContactID}};
push @regList, $name if defined $name;
}
# make sure a region exists, otherwise return undef
return @regList ? \@regList : undef;
},
},
#
# Versions that do not filter out unnamed regions (ContactID=ffffffffffffffff)
# Picasa normally does not add these regions when it saves names to the file.
#
PicasaToMWGRegionUnfiltered => {
Require => {
0 => 'Directory',
1 => 'FileName',
2 => 'ImageWidth',
3 => 'ImageHeight',
},
Desire => {
4 => 'Orientation',
5 => 'FileType',
},
ValueConv => sub {
my ($val, $et) = @_;
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
my $filename = $$val[1];
my @regList;
# convert to local variables for readability, and make
# sure there is a region associated with the current file
my $contactHashRef = \%contactHash;
my $tempArrayRef = $fileHash{$filename} or return undef;
foreach my $tempHash (@$tempArrayRef) {
my @rect = @$tempHash{'X','Y','W','H'};
RotateRegion(\@rect, $$val[4], $$val[5]);
push @regList, {
Area => {
X => $rect[0] + $rect[2] / 2,
Y => $rect[1] + $rect[3] / 2,
W => $rect[2],
H => $rect[3],
Unit => 'normalized',
},
Name => $$contactHashRef{$$tempHash{ContactID}} || 'unnamed',
Type => 'Face',
};
}
# make sure a region exists, otherwise return undef
return @regList ? {
AppliedToDimensions => { W => $$val[2], H => $$val[3], Unit => 'pixel' },
RegionList => \@regList,
} : undef;
},
},
PicasaToMPRegionUnfiltered => {
Require => {
0 => 'Directory',
1 => 'FileName',
},
Desire => {
2 => 'Orientation',
3 => 'FileType',
},
ValueConv => sub {
my ($val, $et) = @_;
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
my $filename = $$val[1];
my @regList;
# convert to local variables for readability, and make
# sure there is a region associated with the current file
my $contactHashRef = \%contactHash;
my $tempArrayRef = $fileHash{$filename} or return undef;
foreach my $tempHash (@$tempArrayRef) {
my @rect = @$tempHash{'X','Y','W','H'};
RotateRegion(\@rect, $$val[2], $$val[3]);
push @regList, {
PersonDisplayName => $$contactHashRef{$$tempHash{ContactID}} || 'unnamed',
Rectangle => join(', ', @rect),
}
}
# make sure a region exists, otherwise return undef
return @regList ? { Regions => \@regList } : undef;
},
},
},
);
#------------------------------------------------------------------------------
1; #end