You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

234 lines
9.6 KiB

#------------------------------------------------------------------------------
# File: convert_regions.config
#
# Description: User-defined Composite tag definitions to allow conversion of
# face regions between Microsoft Windows Live Photo Gallery (WLPG),
# Metadata Working Group (MWG), and IPTC Extension formats
#
# Usage: 1) Convert from MP WLPG or IPTC regions to MWG regions:
#
# exiftool -config convert_regions.config "-RegionInfo<MPRegion2MWGRegion" FILE
#
# 2) Convert from MWG or IPTC to MP WLPG regions:
#
# exiftool -config convert_regions.config "-RegionInfoMP<MWGRegion2MPRegion" FILE
#
# 3) Convert from MWG or MP WLPG to IPTC regions:
#
# exiftool -config convert_regions.config "-ImageRegion<MWGRegion2IPTCRegion" FILE
#
# Requires: ExifTool version 11.74 or later
#
# Revisions: 2012/12/27 - P. Harvey Created
# 2013/02/20 - PH Don't add ignored MP faces
# 2017/02/13 - PH Handle MP regions without Rectangle or Name entries
# 2019/10/26 - PH Added support for the new IPTC ImageRegion
# 2021/05-27 - PH Changed a few tag names and added shortcuts for
# backward compatibility
#
# References: http://www.metadataworkinggroup.org/specs/
#------------------------------------------------------------------------------
%Image::ExifTool::UserDefined = (
'Image::ExifTool::Composite' => {
# create an MWG RegionInfo structure from a Microsoft RegionInfoMP structure
MPRegion2MWGRegion => {
Require => {
0 => 'RegionInfoMP',
1 => 'ImageWidth',
2 => 'ImageHeight',
},
ValueConv => q{
my ($rgn, @newRgns);
foreach $rgn (@{$val[0]{Regions}}) {
my $name = $$rgn{PersonDisplayName};
next unless $$rgn{Rectangle} or defined $name;
my %newRgn = ( Type => 'Face' );
if (defined $name) {
# don't add ignored faces
next if $name eq 'ffffffffffffffff';
$newRgn{Name} = $name;
}
if ($$rgn{Rectangle}) {
my @rect = split /\s*,\s*/, $$rgn{Rectangle};
$newRgn{Area} = {
X => $rect[0] + $rect[2]/2,
Y => $rect[1] + $rect[3]/2,
W => $rect[2],
H => $rect[3],
Unit => 'normalized',
} if @rect == 4;
}
push @newRgns, \%newRgn;
}
return {
AppliedToDimensions => { W => $val[1], H => $val[2], Unit => 'pixel' },
RegionList => \@newRgns,
};
},
},
# create an MWG RegionInfo structure from an IPTC ImageRegion list
IPTCRegion2MWGRegion => {
Name => 'MPRegion2MWGRegion',
Require => {
0 => 'ImageRegion',
1 => 'ImageWidth',
2 => 'ImageHeight',
},
ValueConv => q{
my ($rgn, @newRgns);
my $rgns = ref $val[0] eq 'ARRAY' ? $val[0] : [ $val[0] ];
foreach $rgn (@$rgns) {
my %newRgn = ( Type => 'Face' );
if ($$rgn{RegionBoundary} and $$rgn{RegionBoundary}{RbShape} eq 'rectangle') {
my @rect = @{$$rgn{RegionBoundary}}{'RbX','RbY','RbW','RbH'};
if ($$rgn{RegionBoundary}{RbUnit} eq 'pixel') {
$rect[0] /= $val[1], $rect[2] /= $val[1];
$rect[1] /= $val[2]; $rect[3] /= $val[2];
}
$newRgn{Area} = {
X => $rect[0] + $rect[2]/2,
Y => $rect[1] + $rect[3]/2,
W => $rect[2],
H => $rect[3],
Unit => 'normalized',
};
} else {
next unless defined $$rgn{Name};
}
$newRgn{Name} = $$rgn{Name} if defined $$rgn{Name};
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
MWGRegion2MPRegion => {
Require => 'RegionInfo',
ValueConv => q{
my ($rgn, @newRgns);
foreach $rgn (@{$val[0]{RegionList}}) {
next unless $$rgn{Area} or defined $$rgn{Name};
my %newRgn;
if ($$rgn{Area}) {
my @rect = @{$$rgn{Area}}{'X','Y','W','H'};
$rect[0] -= $rect[2]/2;
$rect[1] -= $rect[3]/2;
$newRgn{Rectangle} = join(', ', @rect);
}
$newRgn{PersonDisplayName} = $$rgn{Name} if defined $$rgn{Name};
push @newRgns, \%newRgn;
}
return { Regions => \@newRgns };
},
},
# create a Microsoft RegionInfoMP structure from an IPTC ImageRegion list
IPTCRegion2MPRegion => {
Name => 'MWGRegion2MPRegion',
Require => {
0 => 'ImageRegion',
1 => 'ImageWidth',
2 => 'ImageHeight',
},
ValueConv => q{
my ($rgn, @newRgns);
my $rgns = ref $val[0] eq 'ARRAY' ? $val[0] : [ $val[0] ];
foreach $rgn (@$rgns) {
my %newRgn;
if ($$rgn{RegionBoundary} and $$rgn{RegionBoundary}{RbShape} eq 'rectangle') {
my @rect = @{$$rgn{RegionBoundary}}{'RbX','RbY','RbW','RbH'};
if ($$rgn{RegionBoundary}{RbUnit} eq 'pixel') {
$rect[0] /= $val[1], $rect[2] /= $val[1];
$rect[1] /= $val[2]; $rect[3] /= $val[2];
}
$newRgn{Rectangle} = join(', ', @rect);
} else {
next unless defined $$rgn{Name};
}
$newRgn{PersonDisplayName} = $$rgn{Name} if defined $$rgn{Name};
push @newRgns, \%newRgn;
}
return { Regions => \@newRgns };
},
},
# create an IPTC ImageRegion list from an MWG RegionInfo structure
MWGRegion2IPTCRegion => {
Require => 'RegionInfo',
ValueConv => q{
my ($rgn, @newRgns);
foreach $rgn (@{$val[0]{RegionList}}) {
next unless $$rgn{Area} or defined $$rgn{Name};
my %newRgn;
if ($$rgn{Area}) {
my @rect = @{$$rgn{Area}}{'X','Y','W','H'};
$rect[0] -= $rect[2]/2;
$rect[1] -= $rect[3]/2;
$newRgn{RegionBoundary} = {
RbShape => 'rectangle',
RbUnit => 'relative',
RbX => $rect[0],
RbY => $rect[1],
RbW => $rect[2],
RbH => $rect[3],
};
}
$newRgn{Name} = $$rgn{Name} if defined $$rgn{Name};
push @newRgns, \%newRgn;
}
return \@newRgns;
},
},
# create an IPTC ImageRegion list from a Microsoft RegionInfoMP structure
MPRegion2IPTCRegion => {
Name => 'MWGRegion2IPTCRegion',
Require => 'RegionInfoMP',
ValueConv => q{
my ($rgn, @newRgns);
foreach $rgn (@{$val[0]{Regions}}) {
my $name = $$rgn{PersonDisplayName};
next unless $$rgn{Rectangle} or defined $name;
my %newRgn;
if (defined $name) {
# don't add ignored faces
next if $name eq 'ffffffffffffffff';
$newRgn{Name} = $name;
}
if ($$rgn{Rectangle}) {
my @rect = split /\s*,\s*/, $$rgn{Rectangle};
$newRgn{RegionBoundary} = {
RbShape => 'rectangle',
RbUnit => 'relative',
RbX => $rect[0],
RbY => $rect[1],
RbW => $rect[2],
RbH => $rect[3],
} if @rect == 4;
}
push @newRgns, \%newRgn;
}
return \@newRgns;
},
},
},
);
%Image::ExifTool::UserDefined::Shortcuts = (
MyRegion => 'MPRegion2MWGRegion',
MyRegion2 => 'IPTCRegion2MWGRegion',
MyRegionMP => 'MWGRegion2MPRegion',
MyRegionMP2 => 'IPTCRegion2MPRegion',
MyRegionIPTC => 'MWGRegion2IPTCRegion',
MyRegionIPTC2 => 'MPRegion2IPTCRegion',
);
1; #end