MIFF.pm 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #------------------------------------------------------------------------------
  2. # File: MIFF.pm
  3. #
  4. # Description: Read Magick Image File Format meta information
  5. #
  6. # Revisions: 06/10/2005 - P. Harvey Created
  7. #
  8. # References: 1) http://www.imagemagick.org/script/miff.php
  9. # 2) http://www.cs.uni.edu/Help/ImageMagick/www/miff.html
  10. #------------------------------------------------------------------------------
  11. package Image::ExifTool::MIFF;
  12. use strict;
  13. use vars qw($VERSION);
  14. use Image::ExifTool qw(:DataAccess :Utils);
  15. $VERSION = '1.07';
  16. # MIFF chunks
  17. %Image::ExifTool::MIFF::Main = (
  18. GROUPS => { 2 => 'Image' },
  19. NOTES => q{
  20. The MIFF (Magick Image File Format) format allows aribrary tag names to be
  21. used. Only the standard tag names are listed below, however ExifTool will
  22. decode any tags found in the image.
  23. },
  24. 'background-color' => 'BackgroundColor',
  25. 'blue-primary' => 'BluePrimary',
  26. 'border-color' => 'BorderColor',
  27. 'matt-color' => 'MattColor',
  28. class => 'Class',
  29. colors => 'Colors',
  30. colorspace => 'ColorSpace',
  31. columns => 'ImageWidth',
  32. compression => 'Compression',
  33. delay => 'Delay',
  34. depth => 'Depth',
  35. dispose => 'Dispose',
  36. gamma => 'Gamma',
  37. 'green-primary' => 'GreenPrimary',
  38. id => 'ID',
  39. iterations => 'Iterations',
  40. label => 'Label',
  41. matte => 'Matte',
  42. montage => 'Montage',
  43. packets => 'Packets',
  44. page => 'Page',
  45. # profile tags. Note the SubDirectory is not used by ProcessMIFF(),
  46. # but is inserted for documentation purposes only
  47. 'profile-APP1' => [
  48. # [this list is just for the sake of the documentation]
  49. {
  50. Name => 'APP1_Profile',
  51. SubDirectory => {
  52. TagTable => 'Image::ExifTool::Exif::Main',
  53. },
  54. },
  55. {
  56. Name => 'APP1_Profile',
  57. SubDirectory => {
  58. TagTable => 'Image::ExifTool::XMP::Main',
  59. },
  60. },
  61. ],
  62. 'profile-exif' => { # haven't seen this, but it would make sense - PH
  63. Name => 'EXIF_Profile',
  64. SubDirectory => {
  65. TagTable => 'Image::ExifTool::Exif::Main',
  66. },
  67. },
  68. 'profile-icc' => {
  69. Name => 'ICC_Profile',
  70. SubDirectory => {
  71. TagTable => 'Image::ExifTool::ICC_Profile::Main',
  72. },
  73. },
  74. 'profile-iptc' => {
  75. Name => 'IPTC_Profile',
  76. SubDirectory => {
  77. TagTable => 'Image::ExifTool::Photoshop::Main',
  78. },
  79. },
  80. 'profile-xmp' => { # haven't seen this, but it would make sense - PH
  81. Name => 'XMP_Profile',
  82. SubDirectory => {
  83. TagTable => 'Image::ExifTool::XMP::Main',
  84. },
  85. },
  86. 'red-primary' => 'RedPrimary',
  87. 'rendering-intent' => 'RenderingIntent',
  88. resolution => 'Resolution',
  89. rows => 'ImageHeight',
  90. scene => 'Scene',
  91. signature => 'Signature',
  92. units => 'Units',
  93. 'white-point' => 'WhitePoint',
  94. );
  95. #------------------------------------------------------------------------------
  96. # Extract meta information from a MIFF image
  97. # Inputs: 0) ExifTool object reference, 1) dirInfo reference
  98. # Returns: 1 on success, 0 if this wasn't a valid MIFF image
  99. sub ProcessMIFF($$)
  100. {
  101. my ($et, $dirInfo) = @_;
  102. my $raf = $$dirInfo{RAF};
  103. my $verbose = $$et{OPTIONS}{Verbose};
  104. my ($hdr, $buff);
  105. # validate the MIFF file (note: MIFF files _may_ begin with other
  106. # characters, but this starting sequence is strongly suggested.)
  107. return 0 unless $raf->Read($hdr, 14) == 14;
  108. return 0 unless $hdr eq 'id=ImageMagick';
  109. $et->SetFileType(); # set the FileType tag
  110. # set end-of-line character sequence to read to end of the TEXT
  111. # section for new-type MIFF files (text ends with Colon+Ctrl-Z)
  112. # Old MIFF files end with Colon+Linefeed, so this will likely
  113. # slurp those entire files, which will be slower, but will work
  114. # OK except that the profile information won't be decoded
  115. local $/ = ":\x1a";
  116. my $mode = '';
  117. my @profiles;
  118. if ($raf->ReadLine($buff)) {
  119. chomp $buff; # remove end-of-line chars
  120. my $tagTablePtr = GetTagTable('Image::ExifTool::MIFF::Main');
  121. my @entries = split ' ', $buff;
  122. unshift @entries, $hdr; # put the ID back in
  123. my ($tag, $val);
  124. foreach (@entries) {
  125. if ($mode eq 'com') {
  126. $mode = '' if /\}$/;
  127. next;
  128. } elsif (/^\{/) {
  129. $mode = 'com'; # read to the end of the comment
  130. next;
  131. }
  132. if ($mode eq 'val') {
  133. $val .= " $_"; # join back together with a space
  134. next unless /\}$/;
  135. $mode = '';
  136. $val =~ s/(^\{|\}$)//g; # remove braces
  137. } elsif (/(.+)=(.+)/) {
  138. ($tag, $val) = ($1, $2);
  139. if ($val =~ /^\{/) {
  140. $mode = 'val'; # read to the end of the value data
  141. next;
  142. }
  143. } elsif (/^:/) {
  144. # this could be the end of an old-style MIFF file
  145. last;
  146. } else {
  147. # something we don't recognize -- stop parsing here
  148. $et->Warn('Unrecognized MIFF data');
  149. last;
  150. }
  151. my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
  152. unless ($tagInfo) {
  153. $tagInfo = { Name => $tag };
  154. AddTagToTable($tagTablePtr, $tag, $tagInfo);
  155. }
  156. $verbose and $et->VerboseInfo($tag, $tagInfo,
  157. Table => $tagTablePtr,
  158. DataPt => \$val,
  159. );
  160. # handle profile tags specially
  161. if ($tag =~ /^profile-(.*)/) {
  162. push @profiles, [$1, $val];
  163. } else {
  164. $et->FoundTag($tagInfo, $val);
  165. }
  166. }
  167. }
  168. # process profile information
  169. foreach (@profiles) {
  170. my ($type, $len) = @{$_};
  171. unless ($len =~ /^\d+$/) {
  172. $et->Warn("Invalid length for $type profile");
  173. last; # don't try to read the rest
  174. }
  175. unless ($raf->Read($buff, $len) == $len) {
  176. $et->Warn("Error reading $type profile ($len bytes)");
  177. next;
  178. }
  179. my $processed = 0;
  180. my %dirInfo = (
  181. Parent => 'PNG',
  182. DataPt => \$buff,
  183. DataPos => $raf->Tell() - $len,
  184. DataLen => $len,
  185. DirStart => 0,
  186. DirLen => $len,
  187. );
  188. if ($type eq 'icc') {
  189. # ICC Profile information
  190. my $tagTablePtr = GetTagTable('Image::ExifTool::ICC_Profile::Main');
  191. $processed = $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
  192. } elsif ($type eq 'iptc') {
  193. if ($buff =~ /^8BIM/) {
  194. # Photoshop information
  195. my $tagTablePtr = GetTagTable('Image::ExifTool::Photoshop::Main');
  196. $processed = $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
  197. }
  198. # I haven't seen 'exif' or 'xmp' profile types yet, but I have seen them
  199. # in newer PNG files so presumably they are possible here as well - PH
  200. } elsif ($type eq 'APP1' or $type eq 'exif' or $type eq 'xmp') {
  201. if ($buff =~ /^$Image::ExifTool::exifAPP1hdr/) {
  202. # APP1 EXIF
  203. my $hdrLen = length($Image::ExifTool::exifAPP1hdr);
  204. $dirInfo{DirStart} += $hdrLen;
  205. $dirInfo{DirLen} -= $hdrLen;
  206. # use the usual position for EXIF data: 12 bytes from start of file
  207. # (this may be wrong, but I can't see where the PNG stores this information)
  208. $dirInfo{Base} = 12; # this is the usual value
  209. $processed = $et->ProcessTIFF(\%dirInfo);
  210. } elsif ($buff =~ /^$Image::ExifTool::xmpAPP1hdr/) {
  211. # APP1 XMP
  212. my $hdrLen = length($Image::ExifTool::xmpAPP1hdr);
  213. my $tagTablePtr = GetTagTable('Image::ExifTool::XMP::Main');
  214. $dirInfo{DirStart} += $hdrLen;
  215. $dirInfo{DirLen} -= $hdrLen;
  216. $processed = $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
  217. }
  218. }
  219. unless ($processed) {
  220. $et->Warn("Unknown MIFF $type profile data");
  221. if ($verbose) {
  222. $et->VerboseDir($type, 0, $len);
  223. $et->VerboseDump(\$buff);
  224. }
  225. }
  226. }
  227. return 1;
  228. }
  229. 1; # end
  230. __END__
  231. =head1 NAME
  232. Image::ExifTool::MIFF - Read Magick Image File Format meta information
  233. =head1 SYNOPSIS
  234. This module is used by Image::ExifTool
  235. =head1 DESCRIPTION
  236. This module contains routines required by Image::ExifTool to read MIFF
  237. (Magick Image File Format) images.
  238. =head1 AUTHOR
  239. Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
  240. This library is free software; you can redistribute it and/or modify it
  241. under the same terms as Perl itself.
  242. =head1 REFERENCES
  243. =over 4
  244. =item L<http://www.imagemagick.org/script/miff.php>
  245. =item L<http://www.cs.uni.edu/Help/ImageMagick/www/miff.html>
  246. =back
  247. =head1 SEE ALSO
  248. L<Image::ExifTool::TagNames/MIFF Tags>,
  249. L<Image::ExifTool(3pm)|Image::ExifTool>
  250. =cut