PhotoMechanic.pm 8.1 KB

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