source: gsdl/trunk/perllib/cpan/Image/ExifTool/WritePhotoshop.pl@ 16842

Last change on this file since 16842 was 16842, checked in by davidb, 16 years ago

ExifTool added to cpan area to support metadata extraction from files such as JPEG. Primarily targetted as Image files (hence the Image folder name decided upon by the ExifTool author) it also can handle video such as flash and audio such as Wav

File size: 9.5 KB
Line 
1#------------------------------------------------------------------------------
2# File: WritePhotoshop.pl
3#
4# Description: Write Photoshop IRB meta information
5#
6# Revisions: 12/17/2004 - P. Harvey Created
7#------------------------------------------------------------------------------
8
9package Image::ExifTool::Photoshop;
10
11use strict;
12
13#------------------------------------------------------------------------------
14# Strip resource name from value prepare resource name for writing into IRB
15# Inputs: 0) tagInfo ref, 1) resource name (padded pascal string), 2) new value ref
16# Returns: none (updates name and value if necessary)
17sub SetResourceName($$$)
18{
19 my ($tagInfo, $name, $valPt) = @_;
20 my $setName = $$tagInfo{SetResourceName};
21 if (defined $setName) {
22 # extract resource name from value
23 if ($$valPt =~ m{.*/#(.{0,255})#/$}s) {
24 $name = $1;
25 # strip name from value
26 $$valPt = substr($$valPt, 0, -4 - length($name));
27 } elsif ($setName eq '1') {
28 return; # use old name
29 } else {
30 $name = $setName;
31 }
32 # convert to padded pascal string
33 $name = chr(length $name) . $name;
34 $name .= "\0" if length($name) & 0x01;
35 $_[1] = $name; # return new name
36 }
37}
38
39#------------------------------------------------------------------------------
40# Write Photoshop IRB resource
41# Inputs: 0) ExifTool object reference, 1) source dirInfo reference,
42# 2) tag table reference
43# Returns: IRB resource data (may be empty if no Photoshop data)
44# Notes: Increments ExifTool CHANGED flag for each tag changed
45sub WritePhotoshop($$$)
46{
47 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
48 $exifTool or return 1; # allow dummy access to autoload this package
49 my $dataPt = $$dirInfo{DataPt};
50 unless ($dataPt) {
51 my $emptyData = '';
52 $dataPt = \$emptyData;
53 }
54 my $start = $$dirInfo{DirStart} || 0;
55 my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $start);
56 my $dirEnd = $start + $dirLen;
57 my $verbose = $exifTool->Options('Verbose');
58 my $out = $exifTool->Options('TextOut');
59 my $newData = '';
60
61 # make a hash of new tag info, keyed on tagID
62 my $newTags = $exifTool->GetNewTagInfoHash($tagTablePtr);
63
64 my ($addDirs, $editDirs) = $exifTool->GetAddDirHash($tagTablePtr);
65
66 SetByteOrder('MM'); # Photoshop is always big-endian
67#
68# rewrite existing tags in the old directory, deleting ones as necessary
69# (the Photoshop directory entries aren't in any particular order)
70#
71 # Format: 0) Type, 4 bytes - '8BIM' (or the rare 'PHUT', 'DCSR' or 'AgHg')
72 # 1) TagID,2 bytes
73 # 2) Name, pascal string padded to even no. bytes
74 # 3) Size, 4 bytes - N
75 # 4) Data, N bytes
76 my ($pos, $value, $size, $tagInfo, $tagID);
77 for ($pos=$start; $pos+8<$dirEnd; $pos+=$size) {
78 # each entry must be on same even byte boundary as directory start
79 ++$pos if ($pos ^ $start) & 0x01;
80 my $type = substr($$dataPt, $pos, 4);
81 if ($type !~ /^(8BIM|PHUT|DCSR|AgHg)$/) {
82 $exifTool->Error("Bad Photoshop IRB resource");
83 undef $newData;
84 last;
85 }
86 $tagID = Get16u($dataPt, $pos + 4);
87 # get resource block name (pascal string padded to an even # of bytes)
88 my $namelen = 1 + Get8u($dataPt, $pos + 6);
89 ++$namelen if $namelen & 0x01;
90 if ($pos + $namelen + 10 > $dirEnd) {
91 $exifTool->Error("Bad APP13 resource block");
92 undef $newData;
93 last;
94 }
95 my $name = substr($$dataPt, $pos + 6, $namelen);
96 $size = Get32u($dataPt, $pos + 6 + $namelen);
97 $pos += $namelen + 10;
98 if ($size + $pos > $dirEnd) {
99 $exifTool->Error("Bad APP13 resource data size $size");
100 undef $newData;
101 last;
102 }
103 if ($$newTags{$tagID} and $type eq '8BIM') {
104 $tagInfo = $$newTags{$tagID};
105 delete $$newTags{$tagID};
106 my $newValueHash = $exifTool->GetNewValueHash($tagInfo);
107 # check to see if we are overwriting this tag
108 $value = substr($$dataPt, $pos, $size);
109 if (Image::ExifTool::IsOverwriting($newValueHash, $value)) {
110 $verbose > 1 and print $out " - Photoshop:$$tagInfo{Name} = '$value'\n";
111 $value = Image::ExifTool::GetNewValues($newValueHash);
112 ++$exifTool->{CHANGED};
113 next unless defined $value; # next if tag is being deleted
114 # set resource name if necessary
115 SetResourceName($tagInfo, $name, \$value);
116 $verbose > 1 and print $out " + Photoshop:$$tagInfo{Name} = '$value'\n";
117 }
118 } else {
119 if ($type eq '8BIM') {
120 $tagInfo = $$editDirs{$tagID};
121 unless ($tagInfo) {
122 # process subdirectory anyway if writable (except EXIF to avoid recursion)
123 # --> this allows IPTC to be processed if found here in TIFF images
124 my $tmpInfo = $exifTool->GetTagInfo($tagTablePtr, $tagID);
125 if ($tmpInfo and $$tmpInfo{SubDirectory} and
126 $tmpInfo->{SubDirectory}->{TagTable} ne 'Image::ExifTool::Exif::Main')
127 {
128 my $table = Image::ExifTool::GetTagTable($tmpInfo->{SubDirectory}->{TagTable});
129 $tagInfo = $tmpInfo if $$table{WRITE_PROC};
130 }
131 }
132 }
133 if ($tagInfo) {
134 $$addDirs{$tagID} and delete $$addDirs{$tagID};
135 my %subdirInfo = (
136 DataPt => $dataPt,
137 DirStart => $pos,
138 DataLen => $dirLen,
139 DirLen => $size,
140 Parent => $$dirInfo{DirName},
141 );
142 my $subTable = Image::ExifTool::GetTagTable($tagInfo->{SubDirectory}->{TagTable});
143 my $writeProc = $tagInfo->{SubDirectory}->{WriteProc};
144 my $newValue = $exifTool->WriteDirectory(\%subdirInfo, $subTable, $writeProc);
145 if (defined $newValue) {
146 next unless length $newValue; # remove subdirectory entry
147 $value = $newValue;
148 SetResourceName($tagInfo, $name, \$value);
149 } else {
150 $value = substr($$dataPt, $pos, $size); # rewrite old directory
151 }
152 } else {
153 $value = substr($$dataPt, $pos, $size);
154 }
155 }
156 my $newSize = length $value;
157 # write this directory entry
158 $newData .= $type . Set16u($tagID) . $name . Set32u($newSize) . $value;
159 $newData .= "\0" if $newSize & 0x01; # must null pad to even byte
160 }
161#
162# write any remaining entries we didn't find in the old directory
163# (might as well write them in numerical tag order)
164#
165 my @tagsLeft = sort { $a <=> $b } keys(%$newTags), keys(%$addDirs);
166 foreach $tagID (@tagsLeft) {
167 my $name = "\0\0";
168 if ($$newTags{$tagID}) {
169 $tagInfo = $$newTags{$tagID};
170 my $newValueHash = $exifTool->GetNewValueHash($tagInfo);
171 $value = Image::ExifTool::GetNewValues($newValueHash);
172 next unless defined $value; # next if tag is being deleted
173 # don't add this tag unless specified
174 next unless Image::ExifTool::IsCreating($newValueHash);
175 $verbose > 1 and print $out " + Photoshop:$$tagInfo{Name} = '$value'\n";
176 ++$exifTool->{CHANGED};
177 } else {
178 $tagInfo = $$addDirs{$tagID};
179 # create new directory
180 my %subdirInfo = (
181 Parent => $$dirInfo{DirName},
182 );
183 my $subTable = Image::ExifTool::GetTagTable($tagInfo->{SubDirectory}->{TagTable});
184 my $writeProc = $tagInfo->{SubDirectory}->{WriteProc};
185 $value = $exifTool->WriteDirectory(\%subdirInfo, $subTable, $writeProc);
186 next unless $value;
187 }
188 # set resource name if necessary
189 SetResourceName($tagInfo, $name, \$value);
190 $size = length($value);
191 # write the new directory entry
192 $newData .= '8BIM' . Set16u($tagID) . $name . Set32u($size) . $value;
193 $newData .= "\0" if $size & 0x01; # must null pad to even numbered byte
194 ++$exifTool->{CHANGED};
195 }
196 return $newData;
197}
198
199
2001; # end
201
202__END__
203
204=head1 NAME
205
206Image::ExifTool::WritePhotoshop.pl - Write Photoshop IRB meta information
207
208=head1 SYNOPSIS
209
210This file is autoloaded by Image::ExifTool::Photoshop.
211
212=head1 DESCRIPTION
213
214This file contains routines to write Photoshop metadata.
215
216=head1 NOTES
217
218Photoshop IRB blocks may have an associated resource name. By default, the
219existing name is preserved when rewriting a resource, and an empty name is
220used when creating a new resource. However, a different resource name may
221be specified by defining a C<SetResourceName> entry in the tag information
222hash. With this defined, a new resource name may be appended to the value
223in the form "VALUE/#NAME#/" (the slashes and hashes are literal). If
224C<SetResourceName> is anything other than '1', the value is used as a
225default resource name, and applied if no appended name is provided.
226
227=head1 AUTHOR
228
229Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
230
231This library is free software; you can redistribute it and/or modify it
232under the same terms as Perl itself.
233
234=head1 SEE ALSO
235
236L<Image::ExifTool::Photoshop(3pm)|Image::ExifTool::Photoshop>,
237L<Image::ExifTool(3pm)|Image::ExifTool>
238
239=cut
Note: See TracBrowser for help on using the repository browser.