1 | #------------------------------------------------------------------------------
|
---|
2 | # File: PhotoMechanic.pm
|
---|
3 | #
|
---|
4 | # Description: Read/write Camera Bits Photo Mechanic information
|
---|
5 | #
|
---|
6 | # Revisions: 10/28/2006 - P. Harvey Created
|
---|
7 | #------------------------------------------------------------------------------
|
---|
8 |
|
---|
9 | package Image::ExifTool::PhotoMechanic;
|
---|
10 |
|
---|
11 | use strict;
|
---|
12 | use vars qw($VERSION);
|
---|
13 | use Image::ExifTool qw(:DataAccess :Utils);
|
---|
14 | use Image::ExifTool::Exif;
|
---|
15 | use Image::ExifTool::IPTC;
|
---|
16 | use Image::ExifTool::XMP;
|
---|
17 |
|
---|
18 | $VERSION = '1.02';
|
---|
19 |
|
---|
20 | sub ProcessPhotoMechanic($$);
|
---|
21 |
|
---|
22 | # color class names
|
---|
23 | my %colorClasses = (
|
---|
24 | 0 => '0 (None)',
|
---|
25 | 1 => '1 (Winner)',
|
---|
26 | 2 => '2 (Winner alt)',
|
---|
27 | 3 => '3 (Superior)',
|
---|
28 | 4 => '4 (Superior alt)',
|
---|
29 | 5 => '5 (Typical)',
|
---|
30 | 6 => '6 (Typical alt)',
|
---|
31 | 7 => '7 (Extras)',
|
---|
32 | 8 => '8 (Trash)',
|
---|
33 | );
|
---|
34 |
|
---|
35 | # main tag table IPTC-format records in PhotoMechanic trailer
|
---|
36 | %Image::ExifTool::PhotoMechanic::Main = (
|
---|
37 | GROUPS => { 2 => 'Image' },
|
---|
38 | PROCESS_PROC => \&Image::ExifTool::IPTC::ProcessIPTC,
|
---|
39 | WRITE_PROC => \&Image::ExifTool::IPTC::WriteIPTC,
|
---|
40 | NOTES => q{
|
---|
41 | The Photo Mechanic trailer contains data in an IPTC-format structure, with
|
---|
42 | soft edit information stored under record number 2.
|
---|
43 | },
|
---|
44 | 2 => {
|
---|
45 | Name => 'SoftEdit',
|
---|
46 | SubDirectory => {
|
---|
47 | TagTable => 'Image::ExifTool::PhotoMechanic::SoftEdit',
|
---|
48 | },
|
---|
49 | },
|
---|
50 | );
|
---|
51 |
|
---|
52 | # raw/preview crop coordinate conversions
|
---|
53 | my %rawCropConv = (
|
---|
54 | ValueConv => '$val / 655.36',
|
---|
55 | ValueConvInv => 'int($val * 655.36 + 0.5)',
|
---|
56 | PrintConv => 'sprintf("%.3f%%",$val)',
|
---|
57 | PrintConvInv => '$val=~tr/ %//d; $val',
|
---|
58 | );
|
---|
59 |
|
---|
60 | # Record 2 -- PhotoMechanic soft edit information
|
---|
61 | %Image::ExifTool::PhotoMechanic::SoftEdit = (
|
---|
62 | GROUPS => { 2 => 'Image' },
|
---|
63 | WRITE_PROC => \&Image::ExifTool::IPTC::WriteIPTC,
|
---|
64 | CHECK_PROC => \&Image::ExifTool::IPTC::CheckIPTC,
|
---|
65 | WRITABLE => 1,
|
---|
66 | FORMAT => 'int32s',
|
---|
67 | 209 => { Name => 'RawCropLeft', %rawCropConv },
|
---|
68 | 210 => { Name => 'RawCropTop', %rawCropConv },
|
---|
69 | 211 => { Name => 'RawCropRight', %rawCropConv },
|
---|
70 | 212 => { Name => 'RawCropBottom', %rawCropConv },
|
---|
71 | 213 => 'ConstrainedCropWidth',
|
---|
72 | 214 => 'ConstrainedCropHeight',
|
---|
73 | 215 => 'FrameNum',
|
---|
74 | 216 => {
|
---|
75 | Name => 'Rotation',
|
---|
76 | PrintConv => {
|
---|
77 | 0 => '0',
|
---|
78 | 1 => '90',
|
---|
79 | 2 => '180',
|
---|
80 | 3 => '270',
|
---|
81 | },
|
---|
82 | },
|
---|
83 | 217 => 'CropLeft',
|
---|
84 | 218 => 'CropTop',
|
---|
85 | 219 => 'CropRight',
|
---|
86 | 220 => 'CropBottom',
|
---|
87 | 221 => {
|
---|
88 | Name => 'Tagged',
|
---|
89 | PrintConv => { 0 => 'No', 1 => 'Yes' },
|
---|
90 | },
|
---|
91 | 222 => {
|
---|
92 | Name => 'ColorClass',
|
---|
93 | PrintConv => \%colorClasses,
|
---|
94 | },
|
---|
95 | 223 => 'Rating',
|
---|
96 | 236 => { Name => 'PreviewCropLeft', %rawCropConv },
|
---|
97 | 237 => { Name => 'PreviewCropTop', %rawCropConv },
|
---|
98 | 238 => { Name => 'PreviewCropRight', %rawCropConv },
|
---|
99 | 239 => { Name => 'PreviewCropBottom', %rawCropConv },
|
---|
100 | );
|
---|
101 |
|
---|
102 | # PhotoMechanic XMP properties
|
---|
103 | %Image::ExifTool::PhotoMechanic::XMP = (
|
---|
104 | GROUPS => { 0 => 'XMP', 1 => 'XMP-photomech', 2 => 'Image' },
|
---|
105 | NAMESPACE => { photomechanic => 'http://ns.camerabits.com/photomechanic/1.0/' },
|
---|
106 | WRITE_PROC => \&Image::ExifTool::XMP::WriteXMP,
|
---|
107 | WRITABLE => 'string',
|
---|
108 | NOTES => q{
|
---|
109 | Below is a list of the observed PhotoMechanic XMP tags. The actual
|
---|
110 | namespace prefix is "photomechanic" but ExifTool shortens this in
|
---|
111 | the "XMP-photomech" family 1 group name.
|
---|
112 | },
|
---|
113 | CountryCode => { Avoid => 1, Groups => { 2 => 'Location' } },
|
---|
114 | EditStatus => { },
|
---|
115 | Prefs => {
|
---|
116 | Notes => 'format is "Tagged:0, ColorClass:1, Rating:2, FrameNum:3"',
|
---|
117 | PrintConv => q{
|
---|
118 | $val =~ s[\s*(\d+):\s*(\d+):\s*(\d+):\s*(\S*)]
|
---|
119 | [Tagged:$1, ColorClass:$2, Rating:$3, FrameNum:$4];
|
---|
120 | return $val;
|
---|
121 | },
|
---|
122 | PrintConvInv => q{
|
---|
123 | $val =~ s[Tagged:\s*(\d+).*ColorClass:\s*(\d+).*Rating:\s*(\d+).*FrameNum:\s*(\S*)]
|
---|
124 | [$1:$2:$3:$4]is;
|
---|
125 | return $val;
|
---|
126 | },
|
---|
127 | },
|
---|
128 | TimeCreated => {
|
---|
129 | Avoid => 1,
|
---|
130 | Groups => { 2 => 'Time' },
|
---|
131 | Shift => 'Time',
|
---|
132 | ValueConv => 'Image::ExifTool::Exif::ExifTime($val)',
|
---|
133 | ValueConvInv => 'Image::ExifTool::IPTC::IptcTime($val)',
|
---|
134 | },
|
---|
135 | );
|
---|
136 |
|
---|
137 | #------------------------------------------------------------------------------
|
---|
138 | # Read/write PhotoMechanic information in a file
|
---|
139 | # Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
---|
140 | # Returns: 1 on success, 0 if this file didn't contain PhotoMechanic information
|
---|
141 | # - updates DataPos to point to start of PhotoMechanic information
|
---|
142 | # - updates DirLen to trailer length
|
---|
143 | sub ProcessPhotoMechanic($$)
|
---|
144 | {
|
---|
145 | my ($exifTool, $dirInfo) = @_;
|
---|
146 | my $raf = $$dirInfo{RAF};
|
---|
147 | my $offset = $$dirInfo{Offset} || 0;
|
---|
148 | my $outfile = $$dirInfo{OutFile};
|
---|
149 | my $verbose = $exifTool->Options('Verbose');
|
---|
150 | my $out = $exifTool->Options('TextOut');
|
---|
151 | my $rtnVal = 0;
|
---|
152 | my ($buff, $footer);
|
---|
153 |
|
---|
154 | for (;;) {
|
---|
155 | # read and validate trailer footer (last 12 bytes)
|
---|
156 | last unless $raf->Seek(-12-$offset, 2) and $raf->Read($footer, 12) == 12;
|
---|
157 | last unless $footer =~ /cbipcbbl$/;
|
---|
158 | my $size = unpack('N', $footer);
|
---|
159 |
|
---|
160 | if ($size & 0x80000000 or not $raf->Seek(-$size-12, 1)) {
|
---|
161 | $exifTool->Warn('Bad PhotoMechanic trailer');
|
---|
162 | last;
|
---|
163 | }
|
---|
164 | unless ($raf->Read($buff, $size) == $size) {
|
---|
165 | $exifTool->Warn('Error reading PhotoMechanic trailer');
|
---|
166 | last;
|
---|
167 | }
|
---|
168 | $rtnVal = 1; # we read the trailer successfully
|
---|
169 |
|
---|
170 | # set variables returned in dirInfo hash
|
---|
171 | $$dirInfo{DataPos} = $raf->Tell() - $size;
|
---|
172 | $$dirInfo{DirLen} = $size + 12;
|
---|
173 |
|
---|
174 | my %dirInfo = (
|
---|
175 | DataPt => \$buff,
|
---|
176 | DataPos => $$dirInfo{DataPos},
|
---|
177 | DirStart => 0,
|
---|
178 | DirLen => $size,
|
---|
179 | Parent => 'PhotoMechanic',
|
---|
180 | );
|
---|
181 | my $tagTablePtr = GetTagTable('Image::ExifTool::PhotoMechanic::Main');
|
---|
182 | if (not $outfile) {
|
---|
183 | # extract trailer information
|
---|
184 | $exifTool->DumpTrailer($dirInfo) if $verbose or $exifTool->{HTML_DUMP};
|
---|
185 | $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
---|
186 | } elsif ($exifTool->{DEL_GROUP}->{PhotoMechanic}) {
|
---|
187 | # delete the trailer
|
---|
188 | $verbose and printf $out " Deleting PhotoMechanic trailer\n";
|
---|
189 | ++$exifTool->{CHANGED};
|
---|
190 | } else {
|
---|
191 | # rewrite the trailer
|
---|
192 | my $newPt;
|
---|
193 | my $newBuff = $exifTool->WriteDirectory(\%dirInfo, $tagTablePtr);
|
---|
194 | if (defined $newBuff) {
|
---|
195 | $newPt = \$newBuff; # write out the modified trailer
|
---|
196 | my $pad = 0x800 - length($newBuff);
|
---|
197 | if ($pad > 0 and not $exifTool->Options('Compact')) {
|
---|
198 | # pad out to 2kB like PhotoMechanic does
|
---|
199 | $newBuff .= "\0" x $pad;
|
---|
200 | }
|
---|
201 | # generate new footer
|
---|
202 | $footer = pack('N', length($$newPt)) . 'cbipcbbl';
|
---|
203 | } else {
|
---|
204 | $newPt = \$buff; # just copy existing trailer
|
---|
205 | }
|
---|
206 | # write out the trailer
|
---|
207 | Write($outfile, $$newPt, $footer) or $rtnVal = -1;
|
---|
208 | }
|
---|
209 | last;
|
---|
210 | }
|
---|
211 | return $rtnVal;
|
---|
212 | }
|
---|
213 |
|
---|
214 | 1; # end
|
---|
215 |
|
---|
216 | __END__
|
---|
217 |
|
---|
218 | =head1 NAME
|
---|
219 |
|
---|
220 | Image::ExifTool::PhotoMechanic - Read/write Photo Mechanic information
|
---|
221 |
|
---|
222 | =head1 SYNOPSIS
|
---|
223 |
|
---|
224 | This module is used by Image::ExifTool
|
---|
225 |
|
---|
226 | =head1 DESCRIPTION
|
---|
227 |
|
---|
228 | This module contains definitions required by Image::ExifTool to read and
|
---|
229 | write information written by the Camera Bits Photo Mechanic software.
|
---|
230 |
|
---|
231 | =head1 AUTHOR
|
---|
232 |
|
---|
233 | Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
|
---|
234 |
|
---|
235 | This library is free software; you can redistribute it and/or modify it
|
---|
236 | under the same terms as Perl itself.
|
---|
237 |
|
---|
238 | =head1 ACKNOWLEDGEMENTS
|
---|
239 |
|
---|
240 | Many thanks to the great support provided by Camera Bits, and in particular
|
---|
241 | for the valuable exchanges with Kirk Baker. Based on this experience, I can
|
---|
242 | say that the technical support offered by Camera Bits is second to none.
|
---|
243 |
|
---|
244 | =head1 SEE ALSO
|
---|
245 |
|
---|
246 | L<Image::ExifTool::TagNames/PhotoMechanic Tags>,
|
---|
247 | L<Image::ExifTool(3pm)|Image::ExifTool>
|
---|
248 |
|
---|
249 | =cut
|
---|
250 |
|
---|