FotoStation.pm 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. #------------------------------------------------------------------------------
  2. # File: FotoStation.pm
  3. #
  4. # Description: Read/write FotoWare FotoStation trailer
  5. #
  6. # Revisions: 10/28/2006 - P. Harvey Created
  7. #------------------------------------------------------------------------------
  8. package Image::ExifTool::FotoStation;
  9. use strict;
  10. use vars qw($VERSION);
  11. use Image::ExifTool qw(:DataAccess :Utils);
  12. $VERSION = '1.04';
  13. sub ProcessFotoStation($$);
  14. %Image::ExifTool::FotoStation::Main = (
  15. PROCESS_PROC => \&ProcessFotoStation,
  16. WRITE_PROC => \&ProcessFotoStation,
  17. GROUPS => { 2 => 'Image' },
  18. NOTES => q{
  19. The following tables define information found in the FotoWare FotoStation
  20. trailer.
  21. },
  22. 0x01 => {
  23. Name => 'IPTC',
  24. SubDirectory => {
  25. TagTable => 'Image::ExifTool::IPTC::Main',
  26. },
  27. },
  28. 0x02 => {
  29. Name => 'SoftEdit',
  30. SubDirectory => {
  31. TagTable => 'Image::ExifTool::FotoStation::SoftEdit',
  32. },
  33. },
  34. 0x03 => {
  35. Name => 'ThumbnailImage',
  36. Groups => { 2 => 'Preview' },
  37. Writable => 1,
  38. RawConv => '$self->ValidateImage(\$val,$tag)',
  39. },
  40. 0x04 => {
  41. Name => 'PreviewImage',
  42. Groups => { 2 => 'Preview' },
  43. Writable => 1,
  44. RawConv => '$self->ValidateImage(\$val,$tag)',
  45. },
  46. );
  47. # crop coordinate conversions
  48. my %cropConv = (
  49. ValueConv => '$val / 1000',
  50. ValueConvInv => '$val * 1000',
  51. PrintConv => '"$val%"',
  52. PrintConvInv => '$val=~tr/ %//d; $val',
  53. );
  54. # soft crop record
  55. %Image::ExifTool::FotoStation::SoftEdit = (
  56. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  57. WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
  58. CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
  59. WRITABLE => 1,
  60. FORMAT => 'int32s',
  61. FIRST_ENTRY => 0,
  62. GROUPS => { 2 => 'Image' },
  63. 0 => {
  64. Name => 'OriginalImageWidth',
  65. },
  66. 1 => 'OriginalImageHeight',
  67. 2 => 'ColorPlanes',
  68. 3 => {
  69. Name => 'XYResolution',
  70. ValueConv => '$val / 1000',
  71. ValueConvInv => '$val * 1000',
  72. },
  73. 4 => {
  74. Name => 'Rotation',
  75. Notes => q{
  76. rotations are stored as degrees CCW * 100, but converted to degrees CW by
  77. ExifTool
  78. },
  79. # raw value is 0, 9000, 18000 or 27000
  80. ValueConv => '$val ? 360 - $val / 100 : 0',
  81. ValueConvInv => '$val ? (360 - $val) * 100 : 0',
  82. },
  83. # 5 Validity Check (0x11222211)
  84. 6 => {
  85. Name => 'CropLeft',
  86. %cropConv,
  87. },
  88. 7 => {
  89. Name => 'CropTop',
  90. %cropConv,
  91. },
  92. 8 => {
  93. Name => 'CropRight',
  94. %cropConv,
  95. },
  96. 9 => {
  97. Name => 'CropBottom',
  98. %cropConv,
  99. },
  100. 11 => {
  101. Name => 'CropRotation',
  102. # raw value in the range -4500 to 4500
  103. ValueConv => '-$val / 100',
  104. ValueConvInv => '-$val * 100',
  105. },
  106. );
  107. #------------------------------------------------------------------------------
  108. # Read/write FotoStation information in a file
  109. # Inputs: 0) ExifTool object reference, 1) dirInfo reference
  110. # Returns: 1 on success, 0 if this file didn't contain FotoStation information
  111. # - updates DataPos to point to start of FotoStation information
  112. # - updates DirLen to trailer length
  113. sub ProcessFotoStation($$)
  114. {
  115. my ($et, $dirInfo) = @_;
  116. $et or return 1; # allow dummy access to autoload this package
  117. my ($buff, $footer, $dirBuff, $tagTablePtr);
  118. my $raf = $$dirInfo{RAF};
  119. my $outfile = $$dirInfo{OutFile};
  120. my $offset = $$dirInfo{Offset} || 0;
  121. my $verbose = $et->Options('Verbose');
  122. my $out = $et->Options('TextOut');
  123. my $rtnVal = 0;
  124. $$dirInfo{DirLen} = 0; # initialize returned trailer length
  125. $raf->Seek(-$offset, 2); # seek to specified offset from end of file
  126. # loop through FotoStation records
  127. for (;;) {
  128. # look for trailer signature
  129. last unless $raf->Seek(-10, 1) and $raf->Read($footer, 10) == 10;
  130. my ($tag, $size, $sig) = unpack('nNN', $footer);
  131. last unless $sig == 0xa1b2c3d4 and $size >= 10 and $raf->Seek(-$size, 1);
  132. $size -= 10; # size of data only
  133. last unless $raf->Read($buff, $size) == $size;
  134. $raf->Seek(-$size, 1);
  135. # set variables returned in dirInfo hash
  136. $$dirInfo{DataPos} = $raf->Tell();
  137. $$dirInfo{DirLen} += $size + 10;
  138. unless ($tagTablePtr) {
  139. $tagTablePtr = GetTagTable('Image::ExifTool::FotoStation::Main');
  140. SetByteOrder('MM'); # necessary for the binary data
  141. $rtnVal = 1; # we found a valid FotoStation trailer
  142. }
  143. unless ($outfile) {
  144. # print verbose trailer information
  145. if ($verbose or $$et{HTML_DUMP}) {
  146. $et->DumpTrailer({
  147. RAF => $raf,
  148. DataPos => $$dirInfo{DataPos},
  149. DirLen => $size + 10,
  150. DirName => "FotoStation_$tag",
  151. });
  152. }
  153. # extract information for this tag
  154. $et->HandleTag($tagTablePtr, $tag, $buff,
  155. DataPt => \$buff,
  156. Start => 0,
  157. Size => $size,
  158. DataPos => $$dirInfo{DataPos},
  159. );
  160. next;
  161. }
  162. if ($$et{DEL_GROUP}{FotoStation}) {
  163. $verbose and print $out " Deleting FotoStation trailer\n";
  164. $verbose = 0; # no more verbose messages after this
  165. ++$$et{CHANGED};
  166. next;
  167. }
  168. # rewrite this information
  169. my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
  170. if ($tagInfo) {
  171. my $newVal;
  172. my $tagName = $$tagInfo{Name};
  173. if ($$tagInfo{SubDirectory}) {
  174. my %subdirInfo = (
  175. DataPt => \$buff,
  176. DirStart => 0,
  177. DirLen => $size,
  178. DataPos => $$dirInfo{DataPos},
  179. DirName => $tagName,
  180. Parent => 'FotoStation',
  181. );
  182. my $subTable = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
  183. $newVal = $et->WriteDirectory(\%subdirInfo, $subTable);
  184. } else {
  185. my $nvHash = $et->GetNewValueHash($tagInfo);
  186. if ($et->IsOverwriting($nvHash) > 0) {
  187. $newVal = $et->GetNewValue($nvHash);
  188. $newVal = '' unless defined $newVal;
  189. if ($verbose > 1) {
  190. my $n = length $newVal;
  191. print $out " - FotoStation:$tagName ($size bytes)\n" if $size;
  192. print $out " + FotoStation:$tagName ($n bytes)\n" if $n;
  193. }
  194. ++$$et{CHANGED};
  195. }
  196. }
  197. if (defined $newVal) {
  198. # note: length may be 0 here, but we write the empty record anyway
  199. $buff = $newVal;
  200. $size = length($newVal) + 10;
  201. $footer = pack('nNN', $tag, $size, $sig);
  202. }
  203. }
  204. if (defined $dirBuff) {
  205. # maintain original record order
  206. $dirBuff = $buff . $footer . $dirBuff;
  207. } else {
  208. $dirBuff = $buff . $footer;
  209. }
  210. }
  211. # write the modified FotoStation trailer
  212. Write($outfile, $dirBuff) or $rtnVal = -1 if $dirBuff;
  213. return $rtnVal;
  214. }
  215. 1; # end
  216. __END__
  217. =head1 NAME
  218. Image::ExifTool::FotoStation - Read/write FotoWare FotoStation trailer
  219. =head1 SYNOPSIS
  220. This module is used by Image::ExifTool
  221. =head1 DESCRIPTION
  222. This module contains definitions required by Image::ExifTool to read and
  223. write information from the FotoWare FotoStation trailer.
  224. =head1 AUTHOR
  225. Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
  226. This library is free software; you can redistribute it and/or modify it
  227. under the same terms as Perl itself.
  228. =head1 ACKNOWLEDGEMENTS
  229. Thanks to Mark Tate for information about the FotoStation data format.
  230. =head1 SEE ALSO
  231. L<Image::ExifTool::TagNames/FotoStation Tags>,
  232. L<Image::ExifTool(3pm)|Image::ExifTool>
  233. =cut