1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
#------------------------------------------------------------------------------
# File: photoshop_paths.config
#
# Description: This config file generates user-defined tags for Photoshop
# paths, and may be used to extract path names and/or Bezier knot
# anchor points, or copy path information from one file to
# another.
#
# The anchor points may be extracted along with the path names by
# setting the "Anchor" user parameter (ie. "-userparam anchor"),
# or by themselves with "AnchorOnly".
#
# 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 (also see the notes below).
#
# Path anchor points are converted to pixel coordinates by the
# Composite PathPixXXX tags, and an "AllPathPix" shortcut is
# provided to represent these tags.
#
# Finally, a Composite PathCount tag is provided to return the
# number of paths in an image, and a TotalPathPoints tag counts
# the total number of path anchor points.
#
# Notes: 1) Print conversion must be disabled to be able to copy the paths
# (via either the -n option, or by adding a "#" to the tag name,
# eg. "-tagsfromfile SRC -allpaths#").
#
# 2) When copying the paths, OriginPathInfo must also be copied
# (otherwise Photoshop may give a "program error" and refuse to
# load the image).
#
# Usage:
#
# 1) Extract Photoshop path names:
#
# exiftool -config photoshop_paths.config -allpaths FILE
#
# 2) Extract Photoshop path names and anchor points:
#
# exiftool -config photoshop_paths.config -userparam anchor -allpaths FILE
#
# 3) Extract Photoshop path anchor points only:
#
# exiftool -config photoshop_paths.config -userparam anchoronly -allpaths FILE
#
# 4) Copy all Photoshop paths from one file (SRC) to another (DST):
# (note that OriginPathInfo must also be copied when copying all paths)
#
# exiftool -config photoshop_paths.config -tagsfromfile SRC -allpaths# -originpathinfo DST
#
# 5) Extract path names and anchor points in pixel coordinates:
#
# exiftool -config photoshop_paths.config -allpathpix FILE
#
# Requires: ExifTool version 9.95 or later
#
# Notes: A "-" before a set of Bezier path points indicates a closed subpath,
# and a "+ indicates the start of an open subpath.
#
# Revisions: 2015/05/07 - P. Harvey Created
# 2016/09/14 - PH Added feature to allow extracting anchor points
# 2017/01/24 - PH Added PathCount and PathPix Composite tags
# 2017/02/02 - PH Added support for copying OriginPathInfo
# 2017/02/22 - PH Fixed problem printing some paths
# 2017/03/19 - PH Added "-" or "+" at the start of closed or open
# subpath respectively
# 2017/06/03 - PH Added TotalPathPoints
# 2017/07/17 - PH Added UniquePathPoints
#
# 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
# http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,6647.0.html
#------------------------------------------------------------------------------
# Print Photoshop path name and/or anchor points
# Inputs: 0) reference to Photoshop path data, 1) ExifTool object reference
# 2-3) optional image width/height to convert anchor points to pixels
# Returns: String with name and/or Bezier knot anchor points
sub PrintPath($$;$$)
{
my ($val, $et, $w, $h) = @_;
my ($pos, $name, @rtn);
my $len = length($$val) - 26;
# recover exiftool-added path name if it exists
if ($$val =~ m{.*/#(.{0,255})#/$}s) {
$name = $1;
$len -= length($1) + 4;
} else {
$name = '<none>';
}
my $anchorOnly = $et->Options(UserParam => 'AnchorOnly');
push @rtn, $name unless $anchorOnly;
# loop through path points and extract anchor points if specified
if ($anchorOnly or $et->Options(UserParam => 'Anchor') or defined $w) {
SetByteOrder('MM');
for ($pos=0; $pos<=$len; $pos+=26) {
my $type = Get16u($val, $pos);
$type == 0 and push(@rtn, '-'), next;
$type == 3 and push(@rtn, '+'), next;
# Bezier knot records are types 1, 2, 4 and 5
next unless {1=>1,2=>1,4=>1,5=>1}->{$type};
# the anchor point is at offset 10 in the Bezier knot record
# (fixed-point values with 24-bits after the decimal point)
my $y = Get32s($val, $pos+10) / 0x1000000; # (vertical component first)
my $x = Get32s($val, $pos+14) / 0x1000000;
if (defined $w and defined $h) {
push @rtn, sprintf('(%g,%g)', $x * $w, $y * $h);
} else {
push @rtn, sprintf('(%g,%g)', $x, $y);
}
}
}
return join ' ', @rtn;
}
%Image::ExifTool::Shortcuts::UserDefined = (
# create "AllPaths" shortcut for all Photoshop path tags
AllPaths => [
map { sprintf "Path%x", $_ } (0x7d0 .. 0xbb5),
],
AllPathPix => [
map { sprintf "PathPix%x", $_ } (0x7d0 .. 0xbb5),
],
);
%Image::ExifTool::UserDefined = (
'Image::ExifTool::Photoshop::Main' => {
0xbb8 => {
Name => 'OriginPathInfo',
Flags => [ qw(Writable Protected Binary SetResourceName) ],
},
# 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 => \&PrintPath,
} } (0x7d0 .. 0xbb5),
},
'Image::ExifTool::Composite' => {
PathCount => {
Desire => {
map { $_-0x7d0 => sprintf('Path%x', $_) } (0x7d0 .. 0xbb5),
},
ValueConv => sub {
my ($val, $self) = @_;
my $count = 0;
my $pts = 0;
my $uniq = 0;
my %uniq;
foreach (@$val) {
next unless defined $_;
++$count;
# determine the total number of path anchor points
my $len = length($$_) - 26;
for ($pos=0; $pos<=$len; $pos+=26) {
SetByteOrder('MM');
my $type = Get16u($_, $pos);
last if $type == 0x2f23; # (start of path name added by ExifTool)
next unless {1=>1,2=>1,4=>1,5=>1}->{$type};
my $pt = substr($$_, $pos+10, 8);
$uniq{$pt} or ++$uniq, $uniq{$pt} = 1;
++$pts;
}
}
$$self{TotalPathPoints} = $pts;
$$self{UniquePathPoints} = $uniq;
return $count;
},
},
UniquePathPoints => {
Require => 'PathCount',
ValueConv => '$$self{UniquePathPoints}',
},
TotalPathPoints => {
Require => 'PathCount',
ValueConv => '$$self{TotalPathPoints}',
},
map { sprintf('PathPix%x', $_) => {
Require => {
0 => 'ImageWidth',
1 => 'ImageHeight',
2 => sprintf('Path%x', $_),
},
Description => sprintf('Path Pix %x', $_),
ValueConv => sub {
my ($val, $et) = @_;
PrintPath($$val[2], $et, $$val[0], $$val[1]);
},
} } (0x7d0 .. 0xbb5),
},
);
1; #end
|