source: main/trunk/greenstone2/perllib/cpan/Image/ExifTool/PSP.pm@ 34921

Last change on this file since 34921 was 34921, checked in by anupama, 3 years ago

Committing the improvements to EmbeddedMetaPlugin's processing of Keywords vs other metadata fields. Keywords were literally stored as arrays of words rather than phrases in PDFs (at least in Diego's sample PDF), whereas other meta fields like Subjects and Creators stored them as arrays of phrases. To get both to work, Kathy updated EXIF to a newer version, to retrieve the actual EXIF values stored in the PDF. And Kathy and Dr Bainbridge came up with a new option that I added called apply_join_before_split_to_metafields that's a regex which can list the metadata fields to apply the join_before_split to and whcih previously always got applied to all metadata fields. Now it's applied to any *Keywords metafields by default, as that's the metafield we have experience of that behaves differently to the others, as it stores by word instead of phrases. Tested on Diego's sample PDF. Diego has double-checked it to works on his sample PDF too, setting the split char to ; and turning on the join_before_split and leaving apply_join_before_split_to_metafields at its default of .*Keywords. File changes are strings.properties for the tooltip, the plugin introducing the option and working with it and Kathy's EXIF updates affecting cpan/File and cpan/Image.

  • Property svn:executable set to *
File size: 9.0 KB
Line 
1#------------------------------------------------------------------------------
2# File: PSP.pm
3#
4# Description: Read Paint Shop Pro meta information
5#
6# Revisions: 2010/01/23 - P. Harvey Created
7#
8# References: 1) http://www.jasc.com/support/kb/articles/pspspec.asp
9#------------------------------------------------------------------------------
10
11package Image::ExifTool::PSP;
12
13use strict;
14use vars qw($VERSION);
15use Image::ExifTool qw(:DataAccess :Utils);
16use Image::ExifTool::Exif;
17
18$VERSION = '1.05';
19
20sub ProcessExtData($$$);
21
22# PSP info
23%Image::ExifTool::PSP::Main = (
24 GROUPS => { 2 => 'Image' },
25 VARS => { ALPHA_FIRST => 1 },
26 NOTES => q{
27 Tags extracted from Paint Shop Pro images (PSP, PSPIMAGE, PSPFRAME,
28 PSPSHAPE, PSPTUBE and TUB extensions).
29 },
30 # FileVersions:
31 # 3.0 => PSP 5
32 # 4.0 => PSP 6
33 # 5.0 => PSP 7
34 # 6.0 => PSP 8
35 # 7.0 => PSP 9
36 # ? => PSP X
37 # ? => PSP X1 (is this the same as X?)
38 # ? => PSP X2
39 # 10.0 => PSP X3 (= PSP 13)
40 FileVersion => { PrintConv => '$val=~tr/ /./; $val' },
41 0 => [
42 {
43 Condition => '$$self{PSPFileVersion} > 3',
44 Name => 'ImageInfo',
45 SubDirectory => {
46 TagTable => 'Image::ExifTool::PSP::Image',
47 Start => 4,
48 },
49 },
50 {
51 Name => 'ImageInfo',
52 SubDirectory => {
53 TagTable => 'Image::ExifTool::PSP::Image',
54 },
55 },
56 ],
57 1 => {
58 Name => 'CreatorInfo',
59 SubDirectory => { TagTable => 'Image::ExifTool::PSP::Creator' },
60 },
61 10 => {
62 Name => 'ExtendedInfo',
63 SubDirectory => { TagTable => 'Image::ExifTool::PSP::Ext' },
64 },
65 # this is inside the composite image bank block (16), which I don't want to parse...
66 #18 => {
67 # Name => 'PreviewImage',
68 # Groups => { 2 => 'Preview' },
69 # RawConv => '$self->ValidateImage(\$val,$tag)',
70 #},
71);
72
73# the PSP image block
74%Image::ExifTool::PSP::Image = (
75 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
76 GROUPS => { 2 => 'Image' },
77 0 => { Name => 'ImageWidth', Format => 'int32u' },
78 4 => { Name => 'ImageHeight', Format => 'int32u' },
79 8 => { Name => 'ImageResolution', Format => 'double' },
80 16 => {
81 Name => 'ResolutionUnit',
82 Format => 'int8u',
83 PrintConv => {
84 0 => 'None',
85 1 => 'inches',
86 2 => 'cm',
87 },
88 },
89 17 => {
90 Name => 'Compression',
91 Format => 'int16u',
92 PrintConv => {
93 0 => 'None',
94 1 => 'RLE',
95 2 => 'LZ77',
96 3 => 'JPEG',
97 },
98 },
99 19 => { Name => 'BitsPerSample',Format => 'int16u' },
100 21 => { Name => 'Planes', Format => 'int16u' },
101 23 => { Name => 'NumColors', Format => 'int32u' },
102);
103
104# the PSP creator data block
105%Image::ExifTool::PSP::Creator = (
106 PROCESS_PROC => \&ProcessExtData,
107 GROUPS => { 2 => 'Image' },
108 PRIORITY => 0, # prefer EXIF if it exists
109 0 => 'Title',
110 1 => {
111 Name => 'CreateDate',
112 Format => 'int32u',
113 Groups => { 2 => 'Time' },
114 ValueConv => 'Image::ExifTool::ConvertUnixTime($val,1)',
115 PrintConv => '$self->ConvertDateTime($val)',
116 },
117 2 => {
118 Name => 'ModifyDate',
119 Format => 'int32u',
120 Groups => { 2 => 'Time' },
121 ValueConv => 'Image::ExifTool::ConvertUnixTime($val,1)',
122 PrintConv => '$self->ConvertDateTime($val)',
123 },
124 3 => {
125 Name => 'Artist',
126 Groups => { 2 => 'Author' },
127 },
128 4 => {
129 Name => 'Copyright',
130 Groups => { 2 => 'Author' },
131 },
132 5 => 'Description',
133 6 => {
134 Name => 'CreatorAppID',
135 Format => 'int32u',
136 PrintConv => {
137 0 => 'Unknown',
138 1 => 'Paint Shop Pro',
139 },
140 },
141 7 => {
142 Name => 'CreatorAppVersion',
143 Format => 'int8u',
144 Count => 4,
145 ValueConv => 'join(" ",reverse split " ", $val)', # low byte first
146 PrintConv => '$val=~tr/ /./; $val',
147 },
148);
149
150# the PSP extended data block
151%Image::ExifTool::PSP::Ext = (
152 PROCESS_PROC => \&ProcessExtData,
153 GROUPS => { 2 => 'Image' },
154 3 => {
155 Name => 'EXIFInfo', #(don't change this name, it is used in the code)
156 SubDirectory => { TagTable => 'Image::ExifTool::Exif::Main' },
157 },
158);
159
160#------------------------------------------------------------------------------
161# Extract information from the extended data block
162# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
163# Returns: 1 on success
164sub ProcessExtData($$$)
165{
166 my ($et, $dirInfo, $tagTablePtr) = @_;
167 my $dataPt = $$dirInfo{DataPt};
168 my $dirLen = $$dirInfo{DirLen};
169 my $pos = 0;
170 # loop through sub-blocks
171 while ($pos + 10 < $dirLen) {
172 unless (substr($$dataPt, $pos, 4) eq "~FL\0") {
173 $et->Warn('Lost synchronization while reading sub blocks');
174 last;
175 }
176 my $tag = Get16u($dataPt, $pos + 4);
177 my $len = Get32u($dataPt, $pos + 6);
178 $pos += 10 + $len;
179 if ($pos > $dirLen) {
180 $et->Warn("Truncated sub block ID=$tag len=$len");
181 last;
182 }
183 next unless $$tagTablePtr{$tag};
184 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag) or next;
185 my $start = $pos - $len;
186 unless ($$tagInfo{Name} eq 'EXIFInfo') {
187 $et->HandleTag($tagTablePtr, $tag, undef,
188 TagInfo => $tagInfo,
189 DataPt => $dataPt,
190 DataPos => $$dirInfo{DataPos},
191 DataLen => length $$dataPt,
192 Start => $start,
193 Size => $len,
194 );
195 next;
196 }
197 # validate EXIF block header and set byte order
198 next unless $len > 14 and substr($$dataPt, $pos - $len, 6) eq "Exif\0\0";
199 next unless SetByteOrder(substr($$dataPt, $start + 6, 2));
200 # This is REALLY annoying... They use a standard TIFF offset to point to
201 # the first IFD, but after that the offsets are relative to the start of
202 # the IFD instead of the TIFF base, which means that I must handle it as a
203 # special case. Dumb, dumb...
204 $start += 14;
205 my %dirInfo = (
206 DirName => 'EXIF',
207 Parent => 'PSP',
208 DataPt => $dataPt,
209 DataPos => -$start, # data position relative to Base
210 DataLen => length $$dataPt,
211 DirStart => $start,
212 Base => $start + $$dirInfo{DataPos}, # absolute base offset
213 Multi => 0,
214 );
215 my $exifTable = GetTagTable($$tagInfo{SubDirectory}{TagTable});
216 Image::ExifTool::Exif::ProcessExif($et, \%dirInfo, $exifTable);
217 SetByteOrder('II');
218 }
219 return 1;
220}
221
222#------------------------------------------------------------------------------
223# Extract information from a PSP file
224# Inputs: 0) ExifTool object reference, 1) dirInfo reference
225# Returns: 1 on success, 0 if this wasn't a valid PSP file
226sub ProcessPSP($$)
227{
228 my ($et, $dirInfo) = @_;
229 my $raf = $$dirInfo{RAF};
230 my ($buff, $tag, $len, $err);
231 return 0 unless $raf->Read($buff, 32) == 32 and
232 $buff eq "Paint Shop Pro Image File\x0a\x1a\0\0\0\0\0" and
233 $raf->Read($buff, 4) == 4;
234 $et->SetFileType();
235 SetByteOrder('II');
236 my $tagTablePtr = GetTagTable('Image::ExifTool::PSP::Main');
237 my @a = unpack('v*', $buff);
238 # figure out block header length for this format PSP file
239 my $hlen = $a[0] > 3 ? 10 : 14;
240 $$et{PSPFileVersion} = $a[0]; # save for use in Condition
241 $et->HandleTag($tagTablePtr, FileVersion => "@a");
242 # loop through blocks in file
243 my $pos = 36;
244 for (;;) {
245 last unless $raf->Read($buff, $hlen) == $hlen;
246 unless ($buff =~ /^~BK\0/) {
247 $et->Warn('Lost synchronization while reading main PSP blocks');
248 last;
249 }
250 $tag = Get16u(\$buff, 4);
251 $len = Get32u(\$buff, $hlen - 4);
252 $pos += $hlen + $len;
253 unless ($$tagTablePtr{$tag}) {
254 $raf->Seek($len, 1) or $err=1, last;
255 next;
256 }
257 $raf->Read($buff, $len) == $len or $err=1, last;
258 $et->HandleTag($tagTablePtr, $tag, $buff,
259 DataPt => \$buff,
260 DataPos => $pos - $len,
261 Size => $len,
262 );
263 }
264 $err and $et->Warn("Truncated main block ID=$tag len=$len");
265 return 1;
266}
267
2681; # end
269
270__END__
271
272=head1 NAME
273
274Image::ExifTool::PSP - Read Paint Shop Pro meta information
275
276=head1 SYNOPSIS
277
278This module is used by Image::ExifTool
279
280=head1 DESCRIPTION
281
282This module contains routines required by Image::ExifTool to extract
283information from Paint Shop Pro images.
284
285=head1 AUTHOR
286
287Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
288
289This library is free software; you can redistribute it and/or modify it
290under the same terms as Perl itself.
291
292=head1 REFERENCES
293
294=over 4
295
296=item L<http://www.jasc.com/support/kb/articles/pspspec.asp>
297
298=back
299
300=head1 SEE ALSO
301
302L<Image::ExifTool::TagNames/PSP Tags>,
303L<Image::ExifTool(3pm)|Image::ExifTool>
304
305=cut
306
Note: See TracBrowser for help on using the repository browser.