OpenEXR.pm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. #------------------------------------------------------------------------------
  2. # File: OpenEXR.pm
  3. #
  4. # Description: Read OpenEXR meta information
  5. #
  6. # Revisions: 2011/12/10 - P. Harvey Created
  7. #
  8. # References: 1) http://www.openexr.com/
  9. #------------------------------------------------------------------------------
  10. package Image::ExifTool::OpenEXR;
  11. use strict;
  12. use vars qw($VERSION);
  13. use Image::ExifTool qw(:DataAccess :Utils);
  14. $VERSION = '1.01';
  15. # supported EXR value format types (other types are extracted as undef binary data)
  16. my %formatType = (
  17. box2f => 'float[4]',
  18. box2i => 'int32s[4]',
  19. chlist => 1,
  20. chromaticities => 'float[8]',
  21. compression => 'int8u',
  22. double => 'double',
  23. envmap => 'int8u',
  24. float => 'float',
  25. 'int' => 'int32s',
  26. keycode => 'int32s[7]',
  27. lineOrder => 'int8u',
  28. m33f => 'float[9]',
  29. m44f => 'float[16]',
  30. rational => 'rational64s',
  31. string => 'string', # incorrect in specification! (no leading int)
  32. stringvector => 1,
  33. tiledesc => 1,
  34. timecode => 'int32u[2]',
  35. v2f => 'float[2]',
  36. v2i => 'int32s[2]',
  37. v3f => 'float[3]',
  38. v3i => 'int32s[3]',
  39. );
  40. # OpenEXR tags
  41. %Image::ExifTool::OpenEXR::Main = (
  42. GROUPS => { 2 => 'Image' },
  43. NOTES => q{
  44. Information extracted from EXR images. See L<http://www.openexr.com/> for
  45. the official specification.
  46. },
  47. _ver => { Name => 'EXRVersion' },
  48. _lay => {
  49. Name => 'Layout',
  50. PrintHex => 1,
  51. PrintConv => { 0 => 'Scan Lines', 0x200 => 'Tiles' },
  52. },
  53. adoptedNeutral => { },
  54. altitude => {
  55. Name => 'GPSAltitude',
  56. Groups => { 2 => 'Location' },
  57. PrintConv => q{
  58. $val = int($val * 10) / 10;
  59. return ($val =~ s/^-// ? "$val m Below" : "$val m Above") . " Sea Level";
  60. },
  61. },
  62. aperture => { PrintConv => 'sprintf("%.1f",$val)' },
  63. channels => { },
  64. chromaticities => { },
  65. capDate => {
  66. Name => 'DateTimeOriginal',
  67. Groups => { 2 => 'Time' },
  68. PrintConv => '$self->ConvertDateTime($val)',
  69. },
  70. comments => { },
  71. compression => {
  72. PrintConvColumns => 2,
  73. PrintConv => {
  74. 0 => 'None',
  75. 1 => 'RLE',
  76. 2 => 'ZIPS',
  77. 3 => 'ZIP',
  78. 4 => 'PIZ',
  79. 5 => 'PXR24',
  80. 6 => 'B44',
  81. 7 => 'B44A',
  82. },
  83. },
  84. dataWindow => { },
  85. displayWindow => { },
  86. envmap => {
  87. Name => 'EnvironmentMap',
  88. PrintConv => {
  89. 0 => 'Latitude/Longitude',
  90. 1 => 'Cube',
  91. },
  92. },
  93. expTime => {
  94. Name => 'ExposureTime',
  95. PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
  96. },
  97. focus => {
  98. Name => 'FocusDistance',
  99. PrintConv => '"$val m"',
  100. },
  101. framesPerSecond => { },
  102. keyCode => { },
  103. isoSpeed => { Name => 'ISO' },
  104. latitude => {
  105. Name => 'GPSLatitude',
  106. Groups => { 2 => 'Location' },
  107. RawConv => 'require Image::ExifTool::GPS; $val', # to load Composite tags and routines
  108. PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
  109. },
  110. lineOrder => {
  111. PrintConv => {
  112. 0 => 'Increasing Y',
  113. 1 => 'Decreasing Y',
  114. 2 => 'Random Y',
  115. },
  116. },
  117. longitude => {
  118. Name => 'GPSLongitude',
  119. Groups => { 2 => 'Location' },
  120. RawConv => 'require Image::ExifTool::GPS; $val', # to load Composite tags and routines
  121. PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
  122. },
  123. lookModTransform => { },
  124. multiView => { },
  125. owner => { Groups => { 2 => 'Author' } },
  126. pixelAspectRatio => { },
  127. preview => { },
  128. renderingTransform => { },
  129. screenWindowCenter => { },
  130. screenWindowWidth => { },
  131. tiles => { },
  132. timeCode => { },
  133. utcOffset => {
  134. Name => 'TimeZone',
  135. Groups => { 2 => 'Time' },
  136. PrintConv => 'TimeZoneString($val / 60)',
  137. },
  138. whiteLuminance => { },
  139. worldToCamera => { },
  140. worldToNDC => { },
  141. wrapmodes => { Name => 'WrapModes' },
  142. xDensity => { Name => 'XResolution' },
  143. # also observed:
  144. # ilut
  145. );
  146. #------------------------------------------------------------------------------
  147. # Extract information from an OpenEXR file
  148. # Inputs: 0) ExifTool object reference, 1) DirInfo reference
  149. # Returns: 1 on success, 0 if this wasn't a valid OpenEXR file
  150. sub ProcessEXR($$)
  151. {
  152. my ($et, $dirInfo) = @_;
  153. my $raf = $$dirInfo{RAF};
  154. my $verbose = $et->Options('Verbose');
  155. my $binary = $et->Options('Binary') || $verbose;
  156. my ($buff, $buf2, $dim);
  157. # verify this is a valid RIFF file
  158. return 0 unless $raf->Read($buff, 8) == 8;
  159. return 0 unless $buff =~ /^\x76\x2f\x31\x01/s;
  160. $et->SetFileType();
  161. SetByteOrder('II');
  162. my $tagTablePtr = GetTagTable('Image::ExifTool::OpenEXR::Main');
  163. # extract information from header
  164. my $ver = unpack('x4V', $buff);
  165. $et->HandleTag($tagTablePtr, '_ver', $ver & 0xff);
  166. $et->HandleTag($tagTablePtr, '_lay', $ver & 0x200);
  167. # extract attributes
  168. for (;;) {
  169. $raf->Read($buff, 68) or last;
  170. last if $buff =~ /^\0/;
  171. unless ($buff =~ /^([^\0]{1,31})\0([^\0]{1,31})\0(.{4})/sg) {
  172. $et->Warn('EXR format error');
  173. last;
  174. }
  175. my ($tag, $type, $size) = ($1, $2, unpack('V', $3));
  176. unless ($raf->Seek(pos($buff) - length($buff), 1)) {
  177. $et->Warn('Seek error');
  178. last;
  179. }
  180. my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
  181. unless ($tagInfo) {
  182. my $name = ucfirst $tag;
  183. $name =~ tr/-_a-zA-Z0-9//dc;
  184. if (length $name <= 1) {
  185. if (length $name) {
  186. $name = "Tag$name";
  187. } else {
  188. $name = 'Invalid';
  189. }
  190. }
  191. $tagInfo = { Name => $name, WasAdded => 1 };
  192. AddTagToTable($tagTablePtr, $tag, $tagInfo);
  193. $et->VPrint(0, $$et{INDENT}, "[adding $tag]\n");
  194. }
  195. my ($val, $success);
  196. my $format = $formatType{$type};
  197. if ($format or $binary) {
  198. $raf->Read($buff, $size) == $size and $success = 1;
  199. if (not $format) {
  200. $val = \$buff; # treat as undef binary data
  201. } elsif ($format ne '1') {
  202. # handle formats which map nicely into ExifTool format codes
  203. if ($format =~ /^(\w+)\[?(\d*)/) {
  204. my ($fmt, $cnt) = ($1, $2);
  205. $cnt = $fmt eq 'string' ? $size : 1 unless $cnt;
  206. $val = ReadValue(\$buff, 0, $fmt, $cnt, $size);
  207. }
  208. # handle other format types
  209. } elsif ($type eq 'tiledesc') {
  210. if ($size >= 9) {
  211. my $x = Get32u(\$buff, 0);
  212. my $y = Get32u(\$buff, 4);
  213. my $mode = Get8u(\$buff, 8);
  214. my $lvl = { 0 => 'One Level', 1 => 'MIMAP Levels', 2 => 'RIPMAP Levels' }->{$mode & 0x0f};
  215. $lvl or $lvl = 'Unknown Levels (' . ($mode & 0xf) . ')';
  216. my $rnd = { 0 => 'Round Down', 1 => 'Round Up' }->{$mode >> 4};
  217. $rnd or $rnd = 'Unknown Rounding (' . ($mode >> 4) . ')';
  218. $val = "${x}x$y; $lvl; $rnd";
  219. }
  220. } elsif ($type eq 'chlist') {
  221. $val = [ ];
  222. while ($buff =~ /\G([^\0]{1,31})\0(.{16})/sg) {
  223. my ($str, $dat) = ($1, $2);
  224. my ($pix,$lin,$x,$y) = unpack('VCx3VV', $dat);
  225. $pix = { 0 => 'int8u', 1 => 'half', 2 => 'float' }->{$pix} || "unknown($pix)";
  226. push @$val, "$str $pix" . ($lin ? ' linear' : '') . " $x $y";
  227. }
  228. } elsif ($type eq 'stringvector') {
  229. $val = [ ];
  230. my $pos = 0;
  231. while ($pos + 4 <= length($buff)) {
  232. my $len = Get32u(\$buff, $pos);
  233. last if $pos + 4 + $len > length($buff);
  234. push @$val, substr($buff, $pos + 4, $len);
  235. $pos += 4 + $len;
  236. }
  237. } else {
  238. $val = \$buff; # (shouldn't happen)
  239. }
  240. } else {
  241. # avoid loading binary data
  242. $val = \ "Binary data $size bytes";
  243. $success = $raf->Seek($size, 1);
  244. }
  245. unless ($success) {
  246. $et->Warn('Truncated or corrupted EXR file');
  247. last;
  248. }
  249. $val = '<bad>' unless defined $val;
  250. # take image dimensions from dataWindow (with displayWindow as backup)
  251. if (($tag eq 'dataWindow' or (not $dim and $tag eq 'displayWindow')) and
  252. $val =~ /^(-?\d+) (-?\d+) (-?\d+) (-?\d+)$/)
  253. {
  254. $dim = [$3 - $1 + 1, $4 - $2 + 1];
  255. }
  256. if ($verbose) {
  257. my $dataPt = ref $val ? $val : \$val,
  258. $et->VerboseInfo($tag, $tagInfo,
  259. Table => $tagTablePtr,
  260. Value => $val,
  261. Size => $size,
  262. Format => $type,
  263. DataPt => \$buff,
  264. Addr => $raf->Tell() - $size,
  265. );
  266. }
  267. $et->FoundTag($tagInfo, $val);
  268. }
  269. if ($dim) {
  270. $et->FoundTag('ImageWidth', $$dim[0]);
  271. $et->FoundTag('ImageHeight', $$dim[1]);
  272. }
  273. return 1;
  274. }
  275. 1; # end
  276. __END__
  277. =head1 NAME
  278. Image::ExifTool::OpenEXR - Read OpenEXR meta information
  279. =head1 SYNOPSIS
  280. This module is used by Image::ExifTool
  281. =head1 DESCRIPTION
  282. This module contains definitions required by Image::ExifTool to extract meta
  283. information from OpenEXR images.
  284. =head1 AUTHOR
  285. Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
  286. This library is free software; you can redistribute it and/or modify it
  287. under the same terms as Perl itself.
  288. =head1 REFERENCES
  289. =over 4
  290. =item L<http://www.openexr.com/documentation.html>
  291. =back
  292. =head1 SEE ALSO
  293. L<Image::ExifTool::TagNames/OpenEXR Tags>,
  294. L<Image::ExifTool(3pm)|Image::ExifTool>
  295. =cut