#------------------------------------------------------------------------------ # 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 { # 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