Leaf.pm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. #------------------------------------------------------------------------------
  2. # File: Leaf.pm
  3. #
  4. # Description: Read Creo Leaf EXIF meta information
  5. #
  6. # Revisions: 09/28/2005 - P. Harvey Created
  7. #------------------------------------------------------------------------------
  8. package Image::ExifTool::Leaf;
  9. use strict;
  10. use vars qw($VERSION);
  11. use Image::ExifTool qw(:DataAccess :Utils);
  12. use Image::ExifTool::Exif;
  13. $VERSION = '1.06';
  14. sub ProcessLeaf($$$);
  15. %Image::ExifTool::Leaf::Main = (
  16. PROCESS_PROC => \&ProcessLeaf,
  17. GROUPS => { 0 => 'Leaf', 2 => 'Camera' },
  18. NOTES => q{
  19. These tags are found in .MOS images from Leaf digital camera backs as
  20. written by Creo Leaf Capture. They exist within the Leaf-specific directory
  21. structure of EXIF tag 0x8606. The tables below list observed Leaf tags,
  22. however ExifTool will extract any tags found in the Leaf directories even if
  23. they don't appear in these tables.
  24. },
  25. icc_camera_profile => {
  26. Name => 'ICC_Profile',
  27. SubDirectory => {
  28. TagTable => 'Image::ExifTool::ICC_Profile::Main',
  29. },
  30. },
  31. icc_rgb_ws_profile => {
  32. Name => 'RGB_Profile',
  33. SubDirectory => {
  34. TagTable => 'Image::ExifTool::ICC_Profile::Main',
  35. },
  36. },
  37. camera_profile => {
  38. Name => 'CameraProfile',
  39. SubDirectory => {
  40. TagTable => 'Image::ExifTool::Leaf::CameraProfile',
  41. },
  42. },
  43. JPEG_preview_data => {
  44. %Image::ExifTool::previewImageTagInfo,
  45. Groups => { 2 => 'Preview' },
  46. },
  47. JPEG_preview_info => 'PreviewInfo',
  48. icc_camera_to_tone_space_flow => {
  49. Name => 'ToneSpaceFlow',
  50. Description => 'ICC To Tone Space Flow',
  51. Format => 'int16u',
  52. },
  53. icc_camera_to_tone_matrix => {
  54. Name => 'ToneMatrix',
  55. Description => 'ICC To Tone Matrix',
  56. Format => 'int8u',
  57. Binary => 1,
  58. },
  59. PDA_histogram_data => {
  60. Name => 'PDAHistogram',
  61. Binary => 1,
  62. },
  63. pattern_ratation_angle => {
  64. Name => 'PatternAngle',
  65. Description => 'Pattern Rotation Angle',
  66. Format => 'int16u',
  67. Notes => '"ratation" is not a typo',
  68. },
  69. back_serial_number => {
  70. Name => 'BackSerial',
  71. Description => 'Back Serial Number',
  72. PrintConv => '$val =~ s/ .*//s; $val',
  73. },
  74. image_offset => { Format => 'int16u' },
  75. );
  76. %Image::ExifTool::Leaf::CameraProfile = (
  77. PROCESS_PROC => \&ProcessLeaf,
  78. GROUPS => { 0 => 'Leaf', 2 => 'Camera' },
  79. CamProf_version => 'CameraProfileVersion',
  80. CamProf_name => 'CameraName',
  81. CamProf_type => 'CameraType',
  82. CamProf_back_type => 'CameraBackType',
  83. CamProf_back_type => {
  84. Name => 'CameraBackType',
  85. },
  86. CamProf_capture_profile => {
  87. SubDirectory => {
  88. TagTable => 'Image::ExifTool::Leaf::CaptureProfile',
  89. },
  90. },
  91. CamProf_image_profile => {
  92. SubDirectory => {
  93. TagTable => 'Image::ExifTool::Leaf::ImageProfile',
  94. },
  95. },
  96. );
  97. %Image::ExifTool::Leaf::CaptureProfile = (
  98. PROCESS_PROC => \&ProcessLeaf,
  99. GROUPS => { 0 => 'Leaf', 2 => 'Image' },
  100. CaptProf_version => {},
  101. CaptProf_name => {},
  102. CaptProf_type => {},
  103. CaptProf_back_type => {},
  104. CaptProf_serial_number => {
  105. Name => 'CaptureSerial',
  106. Description => 'Capture Serial Number',
  107. PrintConv => '$val =~ s/ .*//s; $val',
  108. },
  109. CaptProf_image_offset => {},
  110. CaptProf_luminance_consts => {},
  111. CaptProf_xy_offset_info => 'XYOffsetInfo',
  112. CaptProf_color_matrix => {},
  113. CaptProf_reconstruction_type=> {},
  114. CaptProf_image_fields => {},
  115. CaptProf_image_bounds => {},
  116. CaptProf_number_of_planes => {},
  117. CaptProf_raw_data_rotation => {},
  118. CaptProf_color_averages => {},
  119. CaptProf_mosaic_pattern => {},
  120. CaptProf_dark_correction_type=>{},
  121. CaptProf_right_dark_rect => {},
  122. CaptProf_left_dark_rect => {},
  123. CaptProf_center_dark_rect => {},
  124. CaptProf_CCD_rect => {},
  125. CaptProf_CCD_valid_rect => {},
  126. CaptProf_CCD_video_rect => {},
  127. );
  128. %Image::ExifTool::Leaf::ImageProfile = (
  129. PROCESS_PROC => \&ProcessLeaf,
  130. GROUPS => { 0 => 'Leaf', 2 => 'Image' },
  131. ImgProf_version => {},
  132. ImgProf_name => {},
  133. ImgProf_type => {},
  134. ImgProf_back_type => {},
  135. ImgProf_shoot_setup => {
  136. SubDirectory => {
  137. TagTable => 'Image::ExifTool::Leaf::ShootSetup',
  138. },
  139. },
  140. ImgProf_image_status => {},
  141. ImgProf_rotation_angle => {},
  142. );
  143. %Image::ExifTool::Leaf::ShootSetup = (
  144. PROCESS_PROC => \&ProcessLeaf,
  145. GROUPS => { 0 => 'Leaf', 2 => 'Image' },
  146. ShootObj_version => {},
  147. ShootObj_name => {},
  148. ShootObj_type => {},
  149. ShootObj_back_type => {},
  150. ShootObj_capture_setup => {
  151. SubDirectory => {
  152. TagTable => 'Image::ExifTool::Leaf::CaptureSetup',
  153. },
  154. },
  155. ShootObj_color_setup => {
  156. SubDirectory => {
  157. TagTable => 'Image::ExifTool::Leaf::ColorSetup',
  158. },
  159. },
  160. ShootObj_save_setup => {
  161. SubDirectory => {
  162. TagTable => 'Image::ExifTool::Leaf::SaveSetup',
  163. },
  164. },
  165. ShootObj_camera_setup => {
  166. SubDirectory => {
  167. TagTable => 'Image::ExifTool::Leaf::CameraSetup',
  168. },
  169. },
  170. ShootObj_look_header => {
  171. SubDirectory => {
  172. TagTable => 'Image::ExifTool::Leaf::LookHeader',
  173. },
  174. },
  175. );
  176. %Image::ExifTool::Leaf::CaptureSetup = (
  177. PROCESS_PROC => \&ProcessLeaf,
  178. GROUPS => { 0 => 'Leaf', 2 => 'Image' },
  179. CaptureObj_version => {},
  180. CaptureObj_name => {},
  181. CaptureObj_type => {},
  182. CaptureObj_back_type => {},
  183. CaptureObj_neutals => {
  184. SubDirectory => {
  185. TagTable => 'Image::ExifTool::Leaf::Neutrals',
  186. },
  187. },
  188. CaptureObj_selection => {
  189. SubDirectory => {
  190. TagTable => 'Image::ExifTool::Leaf::Selection',
  191. },
  192. },
  193. CaptureObj_tone_curve => {
  194. SubDirectory => {
  195. TagTable => 'Image::ExifTool::Leaf::ToneCurve',
  196. },
  197. },
  198. CaptureObj_sharpness => {
  199. SubDirectory => {
  200. TagTable => 'Image::ExifTool::Leaf::Sharpness',
  201. },
  202. },
  203. CaptureObj_single_quality => {},
  204. CaptureObj_Multi_quality => {},
  205. );
  206. %Image::ExifTool::Leaf::Neutrals = (
  207. PROCESS_PROC => \&ProcessLeaf,
  208. GROUPS => { 0 => 'Leaf', 2 => 'Image' },
  209. NeutObj_version => {},
  210. NeutObj_name => {},
  211. NeutObj_type => {},
  212. NeutObj_back_type => {},
  213. NeutObj_neutrals => {},
  214. NeutObj_color_casts => {},
  215. NeutObj_shadow_end_points => {},
  216. NeutObj_highlight_end_points => {},
  217. );
  218. %Image::ExifTool::Leaf::Selection = (
  219. PROCESS_PROC => \&ProcessLeaf,
  220. GROUPS => { 0 => 'Leaf', 2 => 'Image' },
  221. SelObj_version => {},
  222. SelObj_name => {},
  223. SelObj_type => {},
  224. SelObj_back_type => {},
  225. SelObj_rect => {},
  226. SelObj_resolution => {},
  227. SelObj_scale => {},
  228. SelObj_locks => {},
  229. SelObj_orientation => {},
  230. );
  231. %Image::ExifTool::Leaf::ToneCurve = (
  232. PROCESS_PROC => \&ProcessLeaf,
  233. GROUPS => { 0 => 'Leaf', 2 => 'Image' },
  234. ToneObj_version => {},
  235. ToneObj_name => {},
  236. ToneObj_type => {},
  237. ToneObj_back_type => {},
  238. ToneObj_npts => {},
  239. ToneObj_tones => {},
  240. ToneObj_gamma => {},
  241. );
  242. %Image::ExifTool::Leaf::Sharpness = (
  243. PROCESS_PROC => \&ProcessLeaf,
  244. GROUPS => { 0 => 'Leaf', 2 => 'Image' },
  245. SharpObj_version => {},
  246. SharpObj_name => {},
  247. SharpObj_type => {},
  248. SharpObj_back_type => {},
  249. SharpObj_sharp_method => {},
  250. SharpObj_data_len => {},
  251. SharpObj_sharp_info => {},
  252. );
  253. %Image::ExifTool::Leaf::ColorSetup = (
  254. PROCESS_PROC => \&ProcessLeaf,
  255. GROUPS => { 0 => 'Leaf', 2 => 'Image' },
  256. ColorObj_version => {},
  257. ColorObj_name => {},
  258. ColorObj_type => {},
  259. ColorObj_back_type => {},
  260. ColorObj_has_ICC => {},
  261. ColorObj_input_profile => {},
  262. ColorObj_output_profile => {},
  263. ColorObj_color_mode => {},
  264. ColorObj_color_type => {},
  265. );
  266. %Image::ExifTool::Leaf::SaveSetup = (
  267. PROCESS_PROC => \&ProcessLeaf,
  268. GROUPS => { 0 => 'Leaf', 2 => 'Other' },
  269. SaveObj_version => {},
  270. SaveObj_name => {},
  271. SaveObj_type => {},
  272. SaveObj_back_type => {},
  273. SaveObj_leaf_auto_active=> {},
  274. SaveObj_leaf_hot_folder => {},
  275. SaveObj_leaf_output_file_type => {},
  276. SaveObj_leaf_auto_base_name => {},
  277. SaveObj_leaf_save_selection => {},
  278. SaveObj_leaf_open_proc_HDR => {},
  279. SaveObj_std_auto_active => {},
  280. SaveObj_std_hot_folder => {},
  281. SaveObj_std_output_file_type => {},
  282. SaveObj_std_output_color_mode => {},
  283. SaveObj_std_output_bit_depth => {},
  284. SaveObj_std_base_name => {},
  285. SaveObj_std_save_selection => {},
  286. SaveObj_std_oxygen => {},
  287. SaveObj_std_open_in_photoshop => {},
  288. SaveObj_std_scaled_output => {},
  289. SaveObj_std_sharpen_output => {},
  290. );
  291. %Image::ExifTool::Leaf::CameraSetup = (
  292. PROCESS_PROC => \&ProcessLeaf,
  293. GROUPS => { 0 => 'Leaf', 2 => 'Camera' },
  294. CameraObj_version => {},
  295. CameraObj_name => {},
  296. CameraObj_type => {},
  297. CameraObj_back_type => {},
  298. CameraObj_ISO_speed => {},
  299. CameraObj_strobe => {},
  300. CameraObj_camera_type => {},
  301. CameraObj_lens_type => {},
  302. CameraObj_lens_ID => {},
  303. );
  304. %Image::ExifTool::Leaf::LookHeader = (
  305. PROCESS_PROC => \&ProcessLeaf,
  306. GROUPS => { 0 => 'Leaf', 2 => 'Other' },
  307. LookHead_version => {},
  308. LookHead_name => {},
  309. LookHead_type => {},
  310. LookHead_back_type => {},
  311. );
  312. # tag table for any unknown Leaf directories
  313. %Image::ExifTool::Leaf::Unknown = (
  314. PROCESS_PROC => \&ProcessLeaf,
  315. GROUPS => { 0 => 'Leaf', 2 => 'Unknown' },
  316. );
  317. # table for Leaf SubIFD entries
  318. %Image::ExifTool::Leaf::SubIFD = (
  319. GROUPS => { 0 => 'MakerNotes', 1 => 'LeafSubIFD', 2 => 'Image'},
  320. WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
  321. NOTES => q{
  322. Leaf writes a TIFF-format sub-IFD inside IFD0 of a MOS image. No tags in
  323. this sub-IFD are currently known, except for tag 0x8606 which really
  324. shouldn't be here anyway (so it doesn't appear in the table below) because
  325. it duplicates a reference to the same data of tag 0x8606 in IFD0.
  326. },
  327. );
  328. # prepare Leaf tables by generating tag 'Name' and table 'NOTES'
  329. {
  330. my @tableList = ( 'Image::ExifTool::Leaf::Main' );
  331. my ($tag, %doneTable);
  332. # keep prefix in tag name of common tags
  333. my %keepPrefix = ( Version=>1, Name=>1, Type=>1, BackType=>1 );
  334. while (@tableList) {
  335. my $table = shift @tableList;
  336. next if $doneTable{$table};
  337. my $prefix = ($table =~ /::Main$/) ? undef : '';
  338. $doneTable{$table} = 1;
  339. no strict 'refs';
  340. $table = \%$table;
  341. use strict 'refs';
  342. foreach $tag (keys %$table) {
  343. my $tagInfo = $$table{$tag};
  344. next unless ref $tagInfo eq 'HASH';
  345. next if $tag eq 'GROUPS';
  346. if (defined $prefix and not $prefix) {
  347. ($prefix = $tag) =~ s/_.*//;
  348. }
  349. unless ($$tagInfo{Name}) {
  350. my $name;
  351. ($name = $tag) =~ s/_(.)/\U$1/g;
  352. if ($prefix) {
  353. $name =~ s/^$prefix//;
  354. $name = $prefix . $name if $keepPrefix{$name};
  355. }
  356. $$tagInfo{Name} = ucfirst($name);
  357. }
  358. next unless $$tagInfo{SubDirectory};
  359. my $subTable = $tagInfo->{SubDirectory}->{TagTable};
  360. next unless $subTable =~ /::Leaf::/;
  361. push @tableList, $subTable;
  362. }
  363. next unless $prefix;
  364. $$table{NOTES} = "All B<Tag ID>'s in the following table have a " .
  365. "leading '${prefix}_' which\nhas been removed.\n";
  366. }
  367. }
  368. #------------------------------------------------------------------------------
  369. # Process Leaf information
  370. # Inputs: 0) ExifTool object reference
  371. # 1) Reference to directory information hash
  372. # 2) Pointer to tag table for this directory
  373. # Returns: 1 on success, otherwise returns 0 and sets a Warning
  374. sub ProcessLeaf($$$)
  375. {
  376. my ($et, $dirInfo, $tagTablePtr) = @_;
  377. my $dataPt = $$dirInfo{DataPt};
  378. my $dirStart = $$dirInfo{DirStart} || 0;
  379. my $dirLen = $$dirInfo{DirLen} || $$dirInfo{DataLen} - $dirStart;
  380. my $dirEnd = $dirStart + $dirLen;
  381. my $verbose = $et->Options('Verbose');
  382. my $pos = $dirStart;
  383. my $hdrLen = 52; # header length for PKTS information
  384. my $success;
  385. $verbose and $et->VerboseDir('Leaf');
  386. for (;;) {
  387. last if $pos + $hdrLen > $dirEnd;
  388. my $header = substr($$dataPt, $pos, $hdrLen);
  389. last unless substr($header, 0, 4) eq 'PKTS';
  390. $success = 1;
  391. my $size = Get32u(\$header, 48);
  392. $pos += $hdrLen;
  393. if ($pos + $size > $dirEnd) {
  394. $et->Warn('Truncated Leaf data');
  395. last;
  396. }
  397. my $tag = substr($header, 8, 40);
  398. $tag =~ s/\0.*//s;
  399. next unless $tag;
  400. my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
  401. # generate tag info for unknown tags
  402. my $val;
  403. if ($tagInfo and $$tagInfo{Format}) {
  404. $val = ReadValue($dataPt, $pos, $$tagInfo{Format}, undef, $size);
  405. } else {
  406. $val = substr($$dataPt, $pos, $size);
  407. }
  408. unless ($tagInfo) {
  409. my $name = ucfirst($tag);
  410. $name =~ s/_(.)/\U$1/g;
  411. if ($val =~ /^PKTS\0\0\0\x01/) {
  412. # also unpack unknown directories
  413. $tagInfo = {
  414. Name => $name,
  415. SubDirectory => { TagTable => 'Image::ExifTool::Leaf::Unknown' },
  416. };
  417. } elsif ($tagTablePtr ne \%Image::ExifTool::Leaf::Main or
  418. $et->Options('Unknown'))
  419. {
  420. $tagInfo = {
  421. Name => $name,
  422. Writable => 0,
  423. PrintConv => 'length($val) > 60 ? substr($val,0,55) . "[...]" : $val',
  424. };
  425. # make tags in main table unknown because they tend to be binary
  426. $$tagInfo{Unknown} = 1 if $tagTablePtr eq \%Image::ExifTool::Leaf::Main;
  427. }
  428. $tagInfo and AddTagToTable($tagTablePtr, $tag, $tagInfo);
  429. }
  430. if ($verbose) {
  431. $et->VerboseInfo($tag, $tagInfo,
  432. Table => $tagTablePtr,
  433. Value => $val,
  434. DataPt => $dataPt,
  435. DataPos => $$dirInfo{DataPos},
  436. Size => $size,
  437. Start => $pos,
  438. );
  439. }
  440. if ($tagInfo) {
  441. if ($$tagInfo{SubDirectory}) {
  442. my %subdirInfo = (
  443. DataPt => $dataPt,
  444. DirLen => $size,
  445. DirStart => $pos,
  446. DataPos => $$dirInfo{DataPos},
  447. DirName => 'Leaf PKTS',
  448. );
  449. my $subTable = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
  450. $et->ProcessDirectory(\%subdirInfo, $subTable);
  451. } else {
  452. $val =~ tr/\n/ /; # translate newlines to spaces
  453. $val =~ s/\0+$//; # remove null terminators
  454. $et->FoundTag($tagInfo, $val);
  455. }
  456. }
  457. $pos += $size;
  458. }
  459. $success or $et->Warn('Bad format Leaf data');
  460. return $success;
  461. }
  462. 1; # end
  463. __END__
  464. =head1 NAME
  465. Image::ExifTool::Leaf - Read Creo Leaf EXIF meta information
  466. =head1 SYNOPSIS
  467. This module is loaded automatically by Image::ExifTool when required.
  468. =head1 DESCRIPTION
  469. This module contains definitions required by Image::ExifTool to interpret
  470. meta information from Leaf digital camera backs written by Creo Leaf
  471. Capture.
  472. =head1 AUTHOR
  473. Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
  474. This library is free software; you can redistribute it and/or modify it
  475. under the same terms as Perl itself.
  476. =head1 SEE ALSO
  477. L<Image::ExifTool::TagNames/Leaf Tags>,
  478. L<Image::ExifTool(3pm)|Image::ExifTool>
  479. =cut