- Timestamp:
- 2021-02-26T19:39:51+13:00 (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone2/perllib/cpan/Image/ExifTool/CanonVRD.pm
r24107 r34921 2 2 # File: CanonVRD.pm 3 3 # 4 # Description: Read/write Canon VRD information4 # Description: Read/write Canon VRD and DR4 information 5 5 # 6 6 # Revisions: 2006/10/30 - P. Harvey Created … … 10 10 # 2010/06/18 - PH Support variable-length CustomPictureStyle data 11 11 # 2010/09/14 - PH Added r/w support for XMP in VRD 12 # 2015/05/16 - PH Added DR4 support (DPP 4.1.50.0) 13 # 2018/03/13 - PH Update to DPP 4.8.20 12 14 # 13 15 # References: 1) Bogdan private communication (Canon DPP v3.4.1.1) 14 # 2) Gert Kello private communi ation (DPP 3.8)16 # 2) Gert Kello private communication (DPP 3.8) 15 17 #------------------------------------------------------------------------------ 16 18 … … 20 22 use vars qw($VERSION); 21 23 use Image::ExifTool qw(:DataAccess :Utils); 22 23 $VERSION = '1.12'; 24 use Image::ExifTool::Canon; 25 26 $VERSION = '1.33'; 24 27 25 28 sub ProcessCanonVRD($$;$); … … 28 31 sub ProcessIHL($$$); 29 32 sub ProcessIHLExif($$$); 33 sub ProcessDR4($$;$); 34 sub SortDR4($$); 30 35 31 36 # map for adding directories to VRD … … 35 40 ); 36 41 37 my %noYes = ( 0 => 'No', 1 => 'Yes' ); 42 my %noYes = ( 43 PrintConvColumns => 2, 44 PrintConv => { 0 => 'No', 1 => 'Yes' }, 45 ); 46 47 # DR4 format codes 48 my %vrdFormat = ( 49 1 => 'int32u', 50 2 => 'string', 51 8 => 'int32u', 52 9 => 'int32s', 53 13 => 'double', 54 33 => 'int32u', # (array) 55 38 => 'double', # (array) 56 # 254 => 'undef', ? 57 255 => 'undef', 58 ); 59 60 # empty VRD header/footer for creating VRD from scratch 61 my $blankHeader = "CANON OPTIONAL DATA\0\0\x01\0\0\0\0\0\0"; 62 my $blankFooter = "CANON OPTIONAL DATA\0" . ("\0" x 42) . "\xff\xd9"; 38 63 39 64 # main tag table blocks in CanonVRD trailer (ref PH) … … 43 68 NOTES => q{ 44 69 Canon Digital Photo Professional writes VRD (Recipe Data) information as a 45 trailer record to JPEG, TIFF, CRW and CR2 images, or as a stand-alone VRD46 file. The tags listed below represent information found in this record.47 The complete VRD data record may be accessed as a block using the Extra48 'CanonVRD' tag, but this tag is not extracted or copied unless specified49 explicitly.70 trailer record to JPEG, TIFF, CRW and CR2 images, or as stand-alone VRD or 71 DR4 files. The tags listed below represent information found in these 72 records. The complete VRD/DR4 data record may be accessed as a block using 73 the Extra 'CanonVRD' or 'CanonDR4' tag, but this tag is not extracted or 74 copied unless specified explicitly. 50 75 }, 51 76 0xffff00f4 => { … … 65 90 TagTable => 'Image::ExifTool::XMP::Main', 66 91 }, 92 }, 93 0xffff00f7 => { 94 Name => 'Edit4Data', 95 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::Edit4' }, 67 96 }, 68 97 ); … … 81 110 1 => { 82 111 Name => 'VRDStampTool', 83 # (size is variable, and obtained from int32u at end of last directory)84 112 Size => 0, # size is variable, and obtained from int32u at directory start 85 113 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::StampTool' }, … … 89 117 Size => undef, # size is the remaining edit data 90 118 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::Ver2' }, 119 }, 120 ); 121 122 # Canon DPP version 4 edit information 123 %Image::ExifTool::CanonVRD::Edit4 = ( 124 WRITE_PROC => \&ProcessEditData, 125 PROCESS_PROC => \&ProcessEditData, 126 VARS => { ID_LABEL => 'Index' }, # change TagID label in documentation 127 NOTES => 'Canon DPP version 4 edit information.', 128 0 => { 129 Name => 'DR4', 130 Size => undef, # size is the remaining edit data 131 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::DR4' }, 91 132 }, 92 133 ); … … 110 151 Name => 'IHL_EXIF', 111 152 Notes => q{ 112 extracted as a block if the Unknownoption is used, or processed as the113 first sub-document with the ExtractEmbeddedoption153 extracted as a block if the L<Unknown|../ExifTool.html#Unknown> option is used, or processed as the 154 first sub-document with the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option 114 155 }, 115 156 Binary => 1, … … 122 163 # (same size as the PreviewImage with DPP 3.0.2.6) 123 164 Name => 'ThumbnailImage', 165 Groups => { 2 => 'Preview' }, 124 166 Binary => 1, 125 167 }, 126 168 4 => { 127 169 Name => 'PreviewImage', 170 Groups => { 2 => 'Preview' }, 128 171 Binary => 1, 129 172 }, 130 173 5 => { 131 174 Name => 'RawCodecVersion', 132 ValueConv => '$val =~ s/\0.*// ; $val', # truncate string at null175 ValueConv => '$val =~ s/\0.*//s; $val', # truncate string at null 133 176 }, 134 177 6 => { … … 157 200 DataMember => 'VRDVersion', 158 201 RawConv => '$$self{VRDVersion} = $val', 159 PrintConv => 'sprintf("%.2f", $val / 100)', 160 }, 161 # 0x006 related somehow to RGB levels 162 0x008 => { 163 Name => 'WBAdjRGBLevels', 164 Format => 'int16u[3]', 202 PrintConv => '$val =~ s/^(\d)(\d*)(\d)$/$1.$2.$3/; $val', 203 }, 204 0x006 => { 205 Name => 'WBAdjRGGBLevels', 206 Format => 'int16u[4]', 165 207 }, 166 208 0x018 => { 167 209 Name => 'WhiteBalanceAdj', 168 210 Format => 'int16u', 211 PrintConvColumns => 2, 169 212 PrintConv => { 170 213 0 => 'Auto', … … 185 228 }, 186 229 # 0x01c similar to 0x006 187 # 0x01e similar to 0x008188 230 0x024 => { 189 231 Name => 'WBFineTuneActive', 190 232 Format => 'int16u', 191 PrintConv => \%noYes,233 %noYes, 192 234 }, 193 235 0x028 => { … … 227 269 Name => 'ToneCurveProperty', 228 270 Format => 'int16u', 271 PrintConvColumns => 2, 229 272 PrintConv => { 230 273 0 => 'Shot Settings', … … 253 296 Name => 'ToneCurveActive', 254 297 Format => 'int16u', 255 PrintConv => \%noYes,298 %noYes, 256 299 }, 257 300 0x113 => { … … 338 381 Name => 'CropActive', 339 382 Format => 'int16u', 340 PrintConv => \%noYes,383 %noYes, 341 384 }, 342 385 0x246 => { … … 377 420 10 => '5:4', 378 421 11 => '1:1', 422 12 => 'Circle', 423 65535 => 'Custom', 379 424 }, 380 425 }, … … 422 467 }, 423 468 }, 424 # (VRD 1.0 edit data ends here -- 0x272 bytes)469 # (VRD 1.0.0 edit data ends here -- 0x272 bytes) 425 470 ); 426 471 … … 443 488 FIRST_ENTRY => 0, 444 489 FORMAT => 'int16s', 445 DATAMEMBER => [ 0x58 ], # (required for writable var-format tags) 490 DATAMEMBER => [ 0x58, 0xdc, 0xdf, 0xe0 ], # (required for DataMember and var-format tags) 491 IS_SUBDIR => [ 0xe0 ], 446 492 GROUPS => { 2 => 'Image' }, 447 493 NOTES => 'Tags added in DPP version 2.0 and later.', 448 494 0x02 => { 449 495 Name => 'PictureStyle', 496 PrintConvColumns => 2, 450 497 PrintConv => { 451 498 0 => 'Standard', … … 459 506 }, 460 507 }, 461 0x03 => { 462 Name => 'IsCustomPictureStyle', 463 PrintConv => \%noYes, 464 }, 508 0x03 => { Name => 'IsCustomPictureStyle', %noYes }, 509 # 0x08: 3 510 # 0x09: 4095 511 # 0x0a: 0 512 # 0x0b: 4095 513 # 0x0c: 0 465 514 0x0d => 'StandardRawColorTone', 466 515 0x0e => 'StandardRawSaturation', 467 516 0x0f => 'StandardRawContrast', 468 0x10 => { 469 Name => 'StandardRawLinear', 470 PrintConv => \%noYes, 471 }, 517 0x10 => { Name => 'StandardRawLinear', %noYes }, 472 518 0x11 => 'StandardRawSharpness', 473 519 0x12 => 'StandardRawHighlightPoint', … … 478 524 0x17 => 'PortraitRawSaturation', 479 525 0x18 => 'PortraitRawContrast', 480 0x19 => { 481 Name => 'PortraitRawLinear', 482 PrintConv => \%noYes, 483 }, 526 0x19 => { Name => 'PortraitRawLinear', %noYes }, 484 527 0x1a => 'PortraitRawSharpness', 485 528 0x1b => 'PortraitRawHighlightPoint', … … 490 533 0x20 => 'LandscapeRawSaturation', 491 534 0x21 => 'LandscapeRawContrast', 492 0x22 => { 493 Name => 'LandscapeRawLinear', 494 PrintConv => \%noYes, 495 }, 535 0x22 => { Name => 'LandscapeRawLinear', %noYes }, 496 536 0x23 => 'LandscapeRawSharpness', 497 537 0x24 => 'LandscapeRawHighlightPoint', … … 502 542 0x29 => 'NeutralRawSaturation', 503 543 0x2a => 'NeutralRawContrast', 504 0x2b => { 505 Name => 'NeutralRawLinear', 506 PrintConv => \%noYes, 507 }, 544 0x2b => { Name => 'NeutralRawLinear', %noYes }, 508 545 0x2c => 'NeutralRawSharpness', 509 546 0x2d => 'NeutralRawHighlightPoint', … … 514 551 0x32 => 'FaithfulRawSaturation', 515 552 0x33 => 'FaithfulRawContrast', 516 0x34 => { 517 Name => 'FaithfulRawLinear', 518 PrintConv => \%noYes, 519 }, 553 0x34 => { Name => 'FaithfulRawLinear', %noYes }, 520 554 0x35 => 'FaithfulRawSharpness', 521 555 0x36 => 'FaithfulRawHighlightPoint', … … 544 578 }, 545 579 0x3c => 'MonochromeContrast', 546 0x3d => { 547 Name => 'MonochromeLinear', 548 PrintConv => \%noYes, 549 }, 580 0x3d => { Name => 'MonochromeLinear', %noYes }, 550 581 0x3e => 'MonochromeSharpness', 551 582 0x3f => 'MonochromeRawHighlightPoint', … … 554 585 0x42 => 'MonochromeOutputShadowPoint', 555 586 0x45 => { Name => 'UnknownContrast', Unknown => 1 }, 556 0x46 => { 557 Name => 'UnknownLinear', 558 Unknown => 1, 559 PrintConv => \%noYes, 560 }, 587 0x46 => { Name => 'UnknownLinear', %noYes, Unknown => 1 }, 561 588 0x47 => { Name => 'UnknownSharpness', Unknown => 1 }, 562 589 0x48 => { Name => 'UnknownRawHighlightPoint', Unknown => 1 }, … … 564 591 0x4a => { Name => 'UnknownOutputHighlightPoint',Unknown => 1 }, 565 592 0x4b => { Name => 'UnknownOutputShadowPoint', Unknown => 1 }, 593 0x4c => 'CustomColorTone', 594 0x4d => 'CustomSaturation', 566 595 0x4e => 'CustomContrast', 567 0x4f => { 568 Name => 'CustomLinear', 569 PrintConv => \%noYes, 570 }, 596 0x4f => { Name => 'CustomLinear', %noYes }, 571 597 0x50 => 'CustomSharpness', 572 598 0x51 => 'CustomRawHighlightPoint', … … 582 608 RawConv => 'length($val) == 2 ? undef : $val', # ignore if no data 583 609 }, 584 # (VRD 2.0 edit data ends here: 178 bytes, index 0x59)610 # (VRD 2.0.0 edit data ends here: 178 bytes, index 0x59) 585 611 0x5e => [{ 586 612 Name => 'ChrominanceNoiseReduction', 587 613 Condition => '$$self{VRDVersion} < 330', 588 Notes => 'VRDVersion prior to 3.3 0',614 Notes => 'VRDVersion prior to 3.3.0', 589 615 PrintConv => { 590 616 0 => 'Off', … … 594 620 },{ #1 595 621 Name => 'ChrominanceNoiseReduction', 596 Notes => 'VRDVersion 3.3 0 or later',622 Notes => 'VRDVersion 3.3.0 or later', 597 623 PrintHex => 1, 598 624 PrintConvColumns => 4, … … 624 650 Name => 'LuminanceNoiseReduction', 625 651 Condition => '$$self{VRDVersion} < 330', 626 Notes => 'VRDVersion prior to 3.3 0',652 Notes => 'VRDVersion prior to 3.3.0', 627 653 PrintConv => { 628 654 0 => 'Off', … … 632 658 },{ #1 633 659 Name => 'LuminanceNoiseReduction', 634 Notes => 'VRDVersion 3.3 0 or later',660 Notes => 'VRDVersion 3.3.0 or later', 635 661 PrintHex => 1, 636 662 PrintConvColumns => 4, … … 662 688 Name => 'ChrominanceNR_TIFF_JPEG', 663 689 Condition => '$$self{VRDVersion} < 330', 664 Notes => 'VRDVersion prior to 3.3 0',690 Notes => 'VRDVersion prior to 3.3.0', 665 691 PrintConv => { 666 692 0 => 'Off', … … 670 696 },{ #1 671 697 Name => 'ChrominanceNR_TIFF_JPEG', 672 Notes => 'VRDVersion 3.3 0 or later',698 Notes => 'VRDVersion 3.3.0 or later', 673 699 PrintHex => 1, 674 700 PrintConvColumns => 4, … … 697 723 }, 698 724 }], 699 # (VRD 3.0 edit data ends here: 196 bytes, index 0x62) 700 0x62 => { 701 Name => 'ChromaticAberrationOn', 702 ValueConv => \%noYes, 703 }, 704 0x63 => { 705 Name => 'DistortionCorrectionOn', 706 ValueConv => \%noYes, 707 }, 708 0x64 => { 709 Name => 'PeripheralIlluminationOn', 710 ValueConv => \%noYes, 711 }, 712 0x65 => { 713 Name => 'ColorBlur', 714 ValueConv => \%noYes, 715 }, 725 # 0x61: 1 726 # (VRD 3.0.0 edit data ends here: 196 bytes, index 0x62) 727 0x62 => { Name => 'ChromaticAberrationOn', %noYes }, 728 0x63 => { Name => 'DistortionCorrectionOn', %noYes }, 729 0x64 => { Name => 'PeripheralIlluminationOn', %noYes }, 730 0x65 => { Name => 'ColorBlur', %noYes }, 716 731 0x66 => { 717 732 Name => 'ChromaticAberration', … … 752 767 ValueConvInv => 'int($val * 10 + 0.5)', 753 768 }, 754 # (VRD 3.4 edit data ends here: 220 bytes, index 0x6e) 755 0x6e => { 756 Name => 'AutoLightingOptimizerOn', 757 PrintConv => \%noYes, 758 }, 769 # (VRD 3.4.0 edit data ends here: 220 bytes, index 0x6e) 770 0x6e => { Name => 'AutoLightingOptimizerOn', %noYes }, 759 771 0x6f => { 760 772 Name => 'AutoLightingOptimizer', … … 766 778 }, 767 779 }, 768 # (VRD 3.5 edit data ends here: 232 bytes, index 0x74) 780 # 0x71: 200 781 # 0x73: 100 782 # (VRD 3.5.0 edit data ends here: 232 bytes, index 0x74) 769 783 0x75 => { 770 784 Name => 'StandardRawHighlight', … … 858 872 Name => 'CheckMark2', 859 873 Format => 'int16u', 874 PrintConvColumns => 2, 860 875 PrintConv => { 861 876 0 => 'Clear', … … 867 882 }, 868 883 }, 869 # (VRD 3.8 edit data ends here: 286 bytes, index 0x8f)884 # (VRD 3.8.0 edit data ends here: 286 bytes, index 0x8f) 870 885 0x90 => { 871 886 Name => 'UnsharpMask', 872 887 PrintConv => { 0 => 'Off', 1 => 'On' }, 873 888 }, 874 0x92 => 'UnsharpMaskStrength', 875 0x94 => 'UnsharpMaskFineness', 876 0x96 => 'UnsharpMaskThreshold', 877 # (VRD 3.91 edit data ends here: 392 bytes, index 0xc4) 889 0x92 => 'StandardUnsharpMaskStrength', 890 0x94 => 'StandardUnsharpMaskFineness', 891 0x96 => 'StandardUnsharpMaskThreshold', 892 0x98 => 'PortraitUnsharpMaskStrength', 893 0x9a => 'PortraitUnsharpMaskFineness', 894 0x9c => 'PortraitUnsharpMaskThreshold', 895 0x9e => 'LandscapeUnsharpMaskStrength', 896 0xa0 => 'LandscapeUnsharpMaskFineness', 897 0xa2 => 'LandscapeUnsharpMaskThreshold', 898 0xa4 => 'NeutraUnsharpMaskStrength', 899 0xa6 => 'NeutralUnsharpMaskFineness', 900 0xa8 => 'NeutralUnsharpMaskThreshold', 901 0xaa => 'FaithfulUnsharpMaskStrength', 902 0xac => 'FaithfulUnsharpMaskFineness', 903 0xae => 'FaithfulUnsharpMaskThreshold', 904 0xb0 => 'MonochromeUnsharpMaskStrength', 905 0xb2 => 'MonochromeUnsharpMaskFineness', 906 0xb4 => 'MonochromeUnsharpMaskThreshold', 907 0xb6 => 'CustomUnsharpMaskStrength', 908 0xb8 => 'CustomUnsharpMaskFineness', 909 0xba => 'CustomUnsharpMaskThreshold', 910 0xbc => 'CustomDefaultUnsharpStrength', 911 0xbe => 'CustomDefaultUnsharpFineness', 912 0xc0 => 'CustomDefaultUnsharpThreshold', 913 # (VRD 3.9.1 edit data ends here: 392 bytes, index 0xc4) 914 # 0xc9: 3 - some RawSharpness 915 # 0xca: 4095 - some RawHighlightPoint 916 # 0xcb: 0 - some RawShadowPoint 917 # 0xcc: 4095 - some OutputHighlightPoint 918 # 0xcd: 0 - some OutputShadowPoint 919 # 0xd1: 3 - some UnsharpMaskStrength 920 # 0xd3: 7 - some UnsharpMaskFineness 921 # 0xd5: 3,4 - some UnsharpMaskThreshold 922 0xd6 => { Name => 'CropCircleActive', %noYes }, 923 0xd7 => 'CropCircleX', 924 0xd8 => 'CropCircleY', 925 0xd9 => 'CropCircleRadius', 926 # 0xda: 0, 1 927 # 0xdb: 100 928 0xdc => { 929 Name => 'DLOOn', 930 DataMember => 'DLOOn', 931 RawConv => '$$self{DLOOn} = $val', 932 %noYes, 933 }, 934 0xdd => 'DLOSetting', 935 # (VRD 3.11.0 edit data ends here: 444 bytes, index 0xde) 936 0xde => { 937 Name => 'DLOShootingDistance', 938 Notes => '100% = infinity', 939 RawConv => '$val == 0x7fff ? undef : $val', 940 ValueConv => '1 - $val / 0x400', 941 ValueConvInv => 'int((1 - $val) * 0x400 + 0.5)', 942 PrintConv => 'sprintf("%.0f%%", $val * 100)', 943 PrintConvInv => 'ToFloat($val) / 100', 944 }, 945 0xdf => { 946 Name => 'DLODataLength', 947 DataMember => 'DLODataLength', 948 Format => 'int32u', 949 Writable => 0, 950 RawConv => '$$self{DLODataLength} = $val', 951 }, 952 0xe0 => { # (yes, this overlaps DLODataLength) 953 Name => 'DLOInfo', 954 # - have seen DLODataLengths of 65536,64869 when DLO is Off, so must test DLOOn flag 955 Condition => '$$self{DLOOn}', 956 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::DLOInfo' }, 957 Hook => '$varSize += $$self{DLODataLength} + 0x16', 958 }, 959 0xe1 => 'CameraRawColorTone', 960 # (VRD 3.11.2 edit data ends here: 452 bytes, index 0xe2, unless DLO is on) 961 0xe2 => 'CameraRawSaturation', 962 0xe3 => 'CameraRawContrast', 963 0xe4 => { Name => 'CameraRawLinear', %noYes }, 964 0xe5 => 'CameraRawSharpness', 965 0xe6 => 'CameraRawHighlightPoint', 966 0xe7 => 'CameraRawShadowPoint', 967 0xe8 => 'CameraRawOutputHighlightPoint', 968 0xe9 => 'CameraRawOutputShadowPoint', 878 969 ); 970 971 # DLO tags (ref PH) 972 %Image::ExifTool::CanonVRD::DLOInfo = ( 973 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 974 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 975 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 976 WRITABLE => 1, 977 FIRST_ENTRY => 1, 978 FORMAT => 'int16s', 979 GROUPS => { 2 => 'Image' }, 980 NOTES => 'Tags added when DLO (Digital Lens Optimizer) is on.', 981 # 0x01 - seen 3112,3140 982 0x04 => 'DLOSettingApplied', 983 0x05 => { 984 Name => 'DLOVersion', #(NC) 985 Format => 'string[10]', 986 }, 987 0x0a => { 988 Name => 'DLOData', 989 LargeTag => 1, # large tag, so avoid storing unnecessarily 990 Notes => 'variable-length Digital Lens Optimizer data, stored in JPEG-like format', 991 Format => 'undef[$$self{DLODataLength}]', 992 Writable => 0, 993 Binary => 1, 994 }, 995 ); 996 997 # VRD version 4 tags (ref PH) 998 %Image::ExifTool::CanonVRD::DR4 = ( 999 PROCESS_PROC => \&ProcessDR4, 1000 WRITE_PROC => \&ProcessDR4, 1001 WRITABLE => 1, 1002 GROUPS => { 2 => 'Image' }, 1003 VARS => { HEX_ID => 1, SORT_PROC => \&SortDR4 }, 1004 NOTES => q{ 1005 Tags written by Canon DPP version 4 in CanonVRD trailers and DR4 files. Each 1006 tag has three associated flag words which are stored with the directory 1007 entry, some of which are extracted as a separate tag, indicated in the table 1008 below by a decimal appended to the tag ID (.0, .1 or .2). 1009 }, 1010 header => { 1011 Name => 'DR4Header', 1012 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::DR4Header' }, 1013 }, 1014 0x10002 => 'Rotation', # left/right rotation 90,180,270 1015 0x10003 => 'AngleAdj', # crop angle 1016 # 0x10018 - fmt=8: 0 1017 # 0x10020 - fmt=2: '' 1018 0x10021 => 'CustomPictureStyle', # (string) 1019 0x10101 => { 1020 Name => 'CheckMark', 1021 PrintConv => { 1022 0 => 'Clear', 1023 1 => 1, 1024 2 => 2, 1025 3 => 3, 1026 4 => 4, 1027 5 => 5, 1028 }, 1029 }, 1030 0x10200 => { 1031 Name => 'WorkColorSpace', 1032 PrintConv => { 1033 1 => 'sRGB', 1034 2 => 'Adobe RGB', 1035 3 => 'Wide Gamut RGB', 1036 4 => 'Apple RGB', 1037 5 => 'ColorMatch RGB', 1038 }, 1039 }, 1040 # 0x10201 - fmt=9: 0 1041 # 0x10f20 - fmt=9: 350 1042 0x20001 => 'RawBrightnessAdj', 1043 0x20101 => { 1044 Name => 'WhiteBalanceAdj', 1045 PrintConvColumns => 2, 1046 PrintConv => { 1047 -1 => 'Manual (Click)', 1048 0 => 'Auto', 1049 1 => 'Daylight', 1050 2 => 'Cloudy', 1051 3 => 'Tungsten', 1052 4 => 'Fluorescent', 1053 5 => 'Flash', 1054 8 => 'Shade', 1055 9 => 'Kelvin', 1056 255 => 'Shot Settings', 1057 }, 1058 }, 1059 0x20102 => 'WBAdjColorTemp', 1060 0x20105 => 'WBAdjMagentaGreen', 1061 0x20106 => 'WBAdjBlueAmber', 1062 0x20125 => { 1063 Name => 'WBAdjRGGBLevels', 1064 PrintConv => '$val =~ s/^\d+ //; $val', # remove first integer (14: what is this for?) 1065 PrintConvInv => '"14 $val"', 1066 }, 1067 0x20200 => { Name => 'GammaLinear', %noYes }, 1068 0x20301 => { 1069 Name => 'PictureStyle', 1070 PrintHex => 1, 1071 PrintConv => { 1072 0x81 => 'Standard', 1073 0x82 => 'Portrait', 1074 0x83 => 'Landscape', 1075 0x84 => 'Neutral', 1076 0x85 => 'Faithful', 1077 0x86 => 'Monochrome', 1078 0x87 => 'Auto', 1079 0x88 => 'Fine Detail', 1080 0xf0 => 'Shot Settings', 1081 0xff => 'Custom', 1082 }, 1083 }, 1084 # 0x20302 - Gamma curve data 1085 0x20303 => 'ContrastAdj', 1086 0x20304 => 'ColorToneAdj', 1087 0x20305 => 'ColorSaturationAdj', 1088 0x20306 => { 1089 Name => 'MonochromeToningEffect', 1090 PrintConv => { 1091 0 => 'None', 1092 1 => 'Sepia', 1093 2 => 'Blue', 1094 3 => 'Purple', 1095 4 => 'Green', 1096 }, 1097 }, 1098 0x20307 => { 1099 Name => 'MonochromeFilterEffect', 1100 PrintConv => { 1101 0 => 'None', 1102 1 => 'Yellow', 1103 2 => 'Orange', 1104 3 => 'Red', 1105 4 => 'Green', 1106 }, 1107 }, 1108 0x20308 => 'UnsharpMaskStrength', 1109 0x20309 => 'UnsharpMaskFineness', 1110 0x2030a => 'UnsharpMaskThreshold', 1111 0x2030b => 'ShadowAdj', 1112 0x2030c => 'HighlightAdj', 1113 0x20310 => { 1114 Name => 'SharpnessAdj', 1115 PrintConv => { 1116 0 => 'Sharpness', 1117 1 => 'Unsharp Mask', 1118 }, 1119 }, 1120 '0x20310.0' => { Name => 'SharpnessAdjOn', %noYes }, 1121 0x20311 => 'SharpnessStrength', 1122 0x20400 => { 1123 Name => 'ToneCurve', 1124 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::ToneCurve' }, 1125 }, 1126 '0x20400.1' => { Name => 'ToneCurveOriginal', %noYes }, 1127 # 0x20401 - fmt=33 (312 bytes) 1128 0x20410 => 'ToneCurveBrightness', 1129 0x20411 => 'ToneCurveContrast', 1130 0x20500 => { 1131 Name => 'AutoLightingOptimizer', 1132 PrintConv => { 1133 0 => 'Low', 1134 1 => 'Standard', 1135 2 => 'Strong', 1136 }, 1137 }, 1138 '0x20500.0' => { 1139 Name => 'AutoLightingOptimizerOn', 1140 Notes => 'ignored if gamma is linear', 1141 %noYes, 1142 }, 1143 # 0x20501 - fmt=13: 0 1144 # 0x20502 - fmt=13: 0 1145 0x20600 => 'LuminanceNoiseReduction', 1146 0x20601 => 'ChrominanceNoiseReduction', 1147 # 0x20650 - fmt=9: 0 (JPG images) 1148 0x20670 => 'ColorMoireReduction', 1149 '0x20670.0' => { Name => 'ColorMoireReductionOn', %noYes }, 1150 0x20701 => { 1151 Name => 'ShootingDistance', 1152 Notes => '100% = infinity', 1153 ValueConv => '$val / 10', 1154 ValueConvInv => '$val * 10', 1155 PrintConv => 'sprintf("%.0f%%", $val * 100)', 1156 PrintConvInv => 'ToFloat($val) / 100', 1157 }, 1158 0x20702 => { 1159 Name => 'PeripheralIllumination', 1160 PrintConv => 'sprintf "%g", $val', 1161 PrintConvInv => '$val', 1162 }, 1163 '0x20702.0' => { Name => 'PeripheralIlluminationOn', %noYes }, 1164 0x20703 => { 1165 Name => 'ChromaticAberration', 1166 PrintConv => 'sprintf "%g", $val', 1167 PrintConvInv => '$val', 1168 }, 1169 '0x20703.0' => { Name => 'ChromaticAberrationOn', %noYes }, 1170 0x20704 => { Name => 'ColorBlurOn', %noYes }, 1171 0x20705 => { 1172 Name => 'DistortionCorrection', 1173 PrintConv => 'sprintf "%g", $val', 1174 PrintConvInv => '$val', 1175 }, 1176 '0x20705.0' => { Name => 'DistortionCorrectionOn', %noYes }, 1177 0x20706 => 'DLOSetting', 1178 '0x20706.0' => { Name => 'DLOOn', %noYes }, 1179 0x20707 => { 1180 Name => 'ChromaticAberrationRed', 1181 PrintConv => 'sprintf "%g", $val', 1182 PrintConvInv => '$val', 1183 }, 1184 0x20708 => { 1185 Name => 'ChromaticAberrationBlue', 1186 PrintConv => 'sprintf "%g", $val', 1187 PrintConvInv => '$val', 1188 }, 1189 0x20709 => { 1190 Name => 'DistortionEffect', 1191 PrintConv => { 1192 0 => 'Shot Settings', 1193 1 => 'Emphasize Linearity', 1194 2 => 'Emphasize Distance', 1195 3 => 'Emphasize Periphery', 1196 4 => 'Emphasize Center', 1197 }, 1198 }, 1199 # 0x20800 - fmt=1: 0 1200 # 0x20801 - fmt=1: 0 1201 0x2070b => { Name => 'DiffractionCorrectionOn', %noYes }, 1202 0x20900 => 'ColorHue', 1203 0x20901 => 'SaturationAdj', 1204 0x20910 => 'RedHSL', 1205 0x20911 => 'OrangeHSL', 1206 0x20912 => 'YellowHSL', 1207 0x20913 => 'GreenHSL', 1208 0x20914 => 'AquaHSL', 1209 0x20915 => 'BlueHSL', 1210 0x20916 => 'PurpleHSL', 1211 0x20917 => 'MagentaHSL', 1212 0x20a00 => { 1213 Name => 'GammaInfo', 1214 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::GammaInfo' }, 1215 }, 1216 # 0x20a01 - Auto picture style settings 1217 # 0x20a02 - Standard picture style settings 1218 # 0x20a03 - Portrait picture style settings 1219 # 0x20a04 - Landscape picture style settings 1220 # 0x20a05 - Neutral picture style settings 1221 # 0x20a06 - Faithful picture style settings 1222 # 0x20a07 - Monochrome picture style settings 1223 # 0x20a08 - (unknown picture style settings) 1224 # 0x20a09 - Custom picture style settings 1225 # 0x20a20 - Fine Detail picture style settings 1226 0x30101 => { 1227 Name => 'CropAspectRatio', 1228 PrintConv => { 1229 0 => 'Free', 1230 1 => 'Custom', 1231 2 => '1:1', 1232 3 => '3:2', 1233 4 => '2:3', 1234 5 => '4:3', 1235 6 => '3:4', 1236 7 => '5:4', 1237 8 => '4:5', 1238 9 => '16:9', 1239 10 => '9:16', 1240 }, 1241 }, 1242 0x30102 => 'CropAspectRatioCustom', 1243 # 0x30103 - fmt=33: "0 0 8" 1244 0xf0100 => { 1245 Name => 'CropInfo', 1246 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::CropInfo' }, 1247 }, 1248 0xf0500 => { 1249 Name => 'CustomPictureStyleData', 1250 Binary => 1, 1251 }, 1252 0xf0510 => { 1253 Name => 'StampInfo', 1254 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::StampInfo' }, 1255 }, 1256 0xf0511 => { 1257 Name => 'DustInfo', 1258 SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::DustInfo' }, 1259 }, 1260 0xf0512 => 'LensFocalLength', 1261 # 0xf0521 - DLO data 1262 # 0xf0520 - DLO data 1263 # 0xf0530 - created when dust delete data applied (4 bytes, all zero) 1264 # 0xf0600 - fmt=253 (2308 bytes, JPG images) 1265 # 0xf0601 - fmt=253 (2308 bytes, JPG images) 1266 # 0x1ff52c - values: 129,130,132 (related to custom picture style somehow) 1267 # to do: 1268 # - find 8-15mm CR2 sample and decode linear distortion effect fine-tune 1269 ); 1270 1271 # Version 4 header information (ref PH) 1272 %Image::ExifTool::CanonVRD::DR4Header = ( 1273 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1274 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1275 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1276 WRITABLE => 1, 1277 FIRST_ENTRY => 0, 1278 FORMAT => 'int32u', 1279 GROUPS => { 2 => 'Image' }, 1280 # 0 - value: 'IIII' (presumably byte order) 1281 # 1 - value: 0x00040004 (currently use this for magic number) 1282 # 2 - value: 6 1283 3 => { 1284 Name => 'DR4CameraModel', 1285 Writable => 'int32u', 1286 PrintHex => 1, 1287 SeparateTable => 'Canon CanonModelID', 1288 PrintConv => \%Image::ExifTool::Canon::canonModelID, 1289 }, 1290 # 4 - value: 3 1291 # 5 - value: 4 1292 # 6 - value: 5 1293 # 7 - DR4 directory entry count 1294 ); 1295 1296 # Version 4 RGB tone curve information (ref PH) 1297 %Image::ExifTool::CanonVRD::ToneCurve = ( 1298 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1299 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1300 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1301 WRITABLE => 1, 1302 FIRST_ENTRY => 0, 1303 FORMAT => 'int32u', 1304 GROUPS => { 2 => 'Image' }, 1305 0x00 => { 1306 Name => 'ToneCurveColorSpace', 1307 PrintConv => { 1308 0 => 'RGB', 1309 1 => 'Luminance', 1310 }, 1311 }, 1312 0x01 => { 1313 Name => 'ToneCurveShape', 1314 PrintConv => { 1315 0 => 'Curve', 1316 1 => 'Straight', 1317 }, 1318 }, 1319 0x03 => { Name => 'ToneCurveInputRange', Format => 'int32u[2]', Notes => '255 max' }, 1320 0x05 => { Name => 'ToneCurveOutputRange', Format => 'int32u[2]', Notes => '255 max' }, 1321 0x07 => { 1322 Name => 'RGBCurvePoints', 1323 Format => 'int32u[21]', 1324 PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)', 1325 PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)', 1326 }, 1327 0x0a => 'ToneCurveX', 1328 0x0b => 'ToneCurveY', 1329 0x2d => { 1330 Name => 'RedCurvePoints', 1331 Format => 'int32u[21]', 1332 PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)', 1333 PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)', 1334 }, 1335 0x53 => { 1336 Name => 'GreenCurvePoints', 1337 Format => 'int32u[21]', 1338 PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)', 1339 PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)', 1340 }, 1341 0x79 => { 1342 Name => 'BlueCurvePoints', 1343 Format => 'int32u[21]', 1344 PrintConv => 'Image::ExifTool::CanonVRD::ToneCurvePrint($val)', 1345 PrintConvInv => 'Image::ExifTool::CanonVRD::ToneCurvePrintInv($val)', 1346 }, 1347 ); 1348 1349 # Version 4 gamma curve information (ref PH) 1350 %Image::ExifTool::CanonVRD::GammaInfo = ( 1351 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1352 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1353 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1354 WRITABLE => 1, 1355 FIRST_ENTRY => 0, 1356 FORMAT => 'double', 1357 GROUPS => { 2 => 'Image' }, 1358 0x02 => 'GammaContrast', 1359 0x03 => 'GammaColorTone', 1360 0x04 => 'GammaSaturation', 1361 0x05 => 'GammaUnsharpMaskStrength', 1362 0x06 => 'GammaUnsharpMaskFineness', 1363 0x07 => 'GammaUnsharpMaskThreshold', 1364 0x08 => 'GammaSharpnessStrength', 1365 0x09 => 'GammaShadow', 1366 0x0a => 'GammaHighlight', 1367 # 0x0b-0x10 are the same as first 6 doubles of tag DR4_0x20302 1368 # 0x0b - value: 14 1369 0x0c => { 1370 Name => 'GammaBlackPoint', 1371 ValueConv => q{ 1372 return 0 if $val <= 0; 1373 $val = log($val / 4.6875) / log(2) + 1; 1374 return abs($val) > 1e-10 ? $val : 0; 1375 }, 1376 ValueConvInv => '$val ? exp(($val - 1) * log(2)) * 4.6876 : 0', 1377 PrintConv => 'sprintf("%+.3f", $val)', 1378 PrintConvInv => '$val', 1379 }, 1380 0x0d => { 1381 Name => 'GammaWhitePoint', 1382 ValueConv => q{ 1383 return $val if $val <= 0; 1384 $val = log($val / 4.6875) / log(2) - 11.77109325169954; 1385 return abs($val) > 1e-10 ? $val : 0; 1386 }, 1387 ValueConvInv => '$val ? exp(($val + 11.77109325169954) * log(2)) * 4.6875 : 0', 1388 PrintConv => 'sprintf("%+.3f", $val)', 1389 PrintConvInv => '$val', 1390 }, 1391 0x0e => { 1392 Name => 'GammaMidPoint', 1393 ValueConv => q{ 1394 return $val if $val <= 0; 1395 $val = log($val / 4.6875) / log(2) - 8; 1396 return abs($val) > 1e-10 ? $val : 0; 1397 }, 1398 ValueConvInv => '$val ? exp(($val + 8) * log(2)) * 4.6876 : 0', 1399 PrintConv => 'sprintf("%+.3f", $val)', 1400 PrintConvInv => '$val', 1401 }, 1402 0x0f => { Name => 'GammaCurveOutputRange', Format => 'double[2]', Notes => '16383 max' }, 1403 ); 1404 1405 # Version 4 crop information (ref PH) 1406 %Image::ExifTool::CanonVRD::CropInfo = ( 1407 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1408 WRITE_PROC => \&Image::ExifTool::WriteBinaryData, 1409 CHECK_PROC => \&Image::ExifTool::CheckBinaryData, 1410 WRITABLE => 1, 1411 FIRST_ENTRY => 0, 1412 FORMAT => 'int32s', 1413 GROUPS => { 2 => 'Image' }, 1414 0 => { Name => 'CropActive', %noYes }, 1415 1 => 'CropRotatedOriginalWidth', 1416 2 => 'CropRotatedOriginalHeight', 1417 3 => 'CropX', 1418 4 => 'CropY', 1419 5 => 'CropWidth', 1420 6 => 'CropHeight', 1421 8 => { 1422 Name => 'CropRotation', 1423 Format => 'double', 1424 PrintConv => 'sprintf("%.7g",$val)', 1425 PrintConvInv => '$val', 1426 }, 1427 0x0a => 'CropOriginalWidth', 1428 0x0b => 'CropOriginalHeight', 1429 # 0x0c double - value: 100 1430 ); 1431 1432 # DR4 Stamp Tool tags (ref PH) 1433 %Image::ExifTool::CanonVRD::StampInfo = ( 1434 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1435 GROUPS => { 2 => 'Image' }, 1436 FORMAT => 'int32u', 1437 FIRST_ENTRY => 0, 1438 0x02 => 'StampToolCount', 1439 ); 1440 1441 # DR4 dust delete information (ref PH) 1442 %Image::ExifTool::CanonVRD::DustInfo = ( 1443 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 1444 GROUPS => { 2 => 'Image' }, 1445 FORMAT => 'int32u', 1446 FIRST_ENTRY => 0, 1447 0x02 => { Name => 'DustDeleteApplied', %noYes }, 1448 ); 1449 1450 #------------------------------------------------------------------------------ 1451 # sort DR4 tag ID's for the documentation 1452 sub SortDR4($$) 1453 { 1454 my ($a, $b) = @_; 1455 my ($aHex, $aDec, $bHex, $bDec); 1456 ($aHex, $aDec) = ($1, $2) if $a =~ /^(0x[0-9a-f]+)?\.?(\d*?)$/; 1457 ($bHex, $bDec) = ($1, $2) if $b =~ /^(0x[0-9a-f]+)?\.?(\d*?)$/; 1458 if ($aHex) { 1459 return 1 unless defined $bDec; # $b is 'header'; 1460 return hex($aHex) <=> hex($bHex) || $aDec <=> $bDec if $bHex; 1461 return hex($aHex) <=> $bDec || 1; 1462 } elsif ($bHex) { 1463 return -1 unless defined $aDec; 1464 return $aDec <=> hex($bHex) || -1; 1465 } else { 1466 return 1 unless defined $bDec; 1467 return -1 unless defined $aDec; 1468 return $aDec <=> $bDec; 1469 } 1470 } 879 1471 880 1472 #------------------------------------------------------------------------------ … … 913 1505 sub ProcessEditData($$$) 914 1506 { 915 my ($e xifTool, $dirInfo, $tagTablePtr) = @_;916 $e xifToolor return 1; # allow dummy access1507 my ($et, $dirInfo, $tagTablePtr) = @_; 1508 $et or return 1; # allow dummy access 917 1509 my $dataPt = $$dirInfo{DataPt}; 918 1510 my $pos = $$dirInfo{DirStart}; … … 920 1512 my $outfile = $$dirInfo{OutFile}; 921 1513 my $dirLen = $$dirInfo{DirLen}; 1514 my $verbose = $et->Options('Verbose'); 1515 my $out = $et->Options('TextOut'); 1516 my $oldChanged = $$et{CHANGED}; 1517 1518 $et->VerboseDir('VRD Edit Data', 0, $dirLen) unless $outfile; 1519 1520 if ($outfile) { 1521 # make a copy for editing in place 1522 my $buff = substr($$dataPt, $pos, $dirLen); 1523 $dataPt = $$dirInfo{DataPt} = \$buff; 1524 $dataPos += $pos; 1525 $pos = $$dirInfo{DirStart} = 0; 1526 } 922 1527 my $dirEnd = $pos + $dirLen; 923 my $verbose = $exifTool->Options('Verbose');924 my $out = $exifTool->Options('TextOut');925 my $oldChanged = $$exifTool{CHANGED};926 927 $exifTool->VerboseDir('VRD Edit Data', 0, $dirLen);928 1528 929 1529 # loop through all records in the edit data … … 935 1535 } else { 936 1536 $recLen = Get32u($dataPt, $pos); 1537 # (DR4 has a null terminator) 1538 last if $recLen == 0 and $pos + 4 == $dirEnd; 937 1539 } 938 1540 $pos += 4; # move to start of record 939 1541 if ($pos + $recLen > $dirEnd) { 940 $e xifTool->Warn('Possibly corrupt CanonVRD Edit record');1542 $et->Warn('Possibly corrupt CanonVRD Edit record'); 941 1543 $err = 1; 942 1544 last; 943 1545 } 1546 my $saveRecLen = $recLen; 944 1547 if ($verbose > 1 and not $outfile) { 945 printf $out "$$e xifTool{INDENT}CanonVRD Edit record ($recLen bytes at offset 0x%x)\n",1548 printf $out "$$et{INDENT}CanonVRD Edit record ($recLen bytes at offset 0x%x)\n", 946 1549 $pos + $dataPos; 1550 $et->VerboseDump($dataPt, Len => $recLen, Start => $pos, Addr => $pos + $dataPos) if $recNum; 947 1551 } 948 1552 … … 951 1555 952 1556 # process VRD edit information 953 my $subTablePtr = GetTagTable('Image::ExifTool::CanonVRD::Edit');1557 my $subTablePtr = $tagTablePtr; 954 1558 my $index; 955 my $editData = substr($$dataPt, $pos, $recLen);956 1559 my %subdirInfo = ( 957 DataPt => \$editData, 958 DataPos => $dataPos + $pos, 1560 DataPt => $dataPt, 1561 DataPos => $dataPos, 1562 DirStart => $pos, 1563 DirLen => $recLen, 1564 OutFile => $outfile, 959 1565 ); 960 my $s tart = 0;1566 my $subStart = 0; 961 1567 # loop through various sections of the VRD edit data 962 1568 for ($index=0; ; ++$index) { 963 1569 my $tagInfo = $$subTablePtr{$index} or last; 964 my $ dirLen;965 my $maxLen = $recLen - $s tart;1570 my $subLen; 1571 my $maxLen = $recLen - $subStart; 966 1572 if ($$tagInfo{Size}) { 967 $ dirLen = $$tagInfo{Size};1573 $subLen = $$tagInfo{Size}; 968 1574 } elsif (defined $$tagInfo{Size}) { 969 # get size from int32u at $s tart970 last unless $s tart + 4 <= $recLen;971 $ dirLen = Get32u(\$editData, $start);972 $s tart += 4; # skip the length word1575 # get size from int32u at $subStart 1576 last unless $subStart + 4 <= $recLen; 1577 $subLen = Get32u($dataPt, $subStart + $pos); 1578 $subStart += 4; # skip the length word 973 1579 } else { 974 $ dirLen = $maxLen;1580 $subLen = $maxLen; 975 1581 } 976 $ dirLen > $maxLen and $dirLen = $maxLen;977 if ($ dirLen) {978 my $subTable = GetTagTable($ tagInfo->{SubDirectory}->{TagTable});1582 $subLen > $maxLen and $subLen = $maxLen; 1583 if ($subLen) { 1584 my $subTable = GetTagTable($$tagInfo{SubDirectory}{TagTable}); 979 1585 my $subName = $$tagInfo{Name}; 980 $subdirInfo{DirStart} = $s tart;981 $subdirInfo{DirLen} = $ dirLen;1586 $subdirInfo{DirStart} = $subStart + $pos; 1587 $subdirInfo{DirLen} = $subLen; 982 1588 $subdirInfo{DirName} = $subName; 983 1589 if ($outfile) { 984 1590 # rewrite this section of the VRD edit information 985 1591 $verbose and print $out " Rewriting Canon $subName\n"; 986 my $newVal = $exifTool->WriteDirectory(\%subdirInfo, $subTable); 987 substr($$dataPt, $pos+$start, $dirLen) = $newVal if $newVal; 1592 my $newVal = $et->WriteDirectory(\%subdirInfo, $subTable); 1593 if ($newVal) { 1594 my $sizeDiff = length($newVal) - $subLen; 1595 substr($$dataPt, $pos+$subStart, $subLen) = $newVal; 1596 if ($sizeDiff) { 1597 $subLen = length $newVal; 1598 $recLen += $sizeDiff; 1599 $dirEnd += $sizeDiff; 1600 $dirLen += $sizeDiff; 1601 } 1602 } 988 1603 } else { 989 $e xifTool->VPrint(0, "$$exifTool{INDENT}$subName (SubDirectory) -->\n");990 $e xifTool->VerboseDump(\$editData,991 Start => $ start,992 Addr => $dataPos + $pos + $s tart,993 Len => $ dirLen,1604 $et->VPrint(0, "$$et{INDENT}$subName (SubDirectory) -->\n"); 1605 $et->VerboseDump($dataPt, 1606 Start => $pos + $subStart, 1607 Addr => $dataPos + $pos + $subStart, 1608 Len => $subLen, 994 1609 ); 995 1610 # extract tags from this section of the VRD edit information 996 $e xifTool->ProcessDirectory(\%subdirInfo, $subTable);1611 $et->ProcessDirectory(\%subdirInfo, $subTable); 997 1612 } 998 1613 } 999 1614 # next section starts at the end of this one 1000 $start += $dirLen; 1615 $subStart += $subLen; 1616 } 1617 if ($outfile and $saveRecLen ne $recLen) { 1618 # update record length if necessary 1619 Set32u($recLen, $dataPt, $pos - 4) 1001 1620 } 1002 1621 } 1003 1622 if ($outfile) { 1004 return undef if $oldChanged == $$e xifTool{CHANGED};1623 return undef if $oldChanged == $$et{CHANGED}; 1005 1624 return substr($$dataPt, $$dirInfo{DirStart}, $dirLen); 1006 1625 } … … 1014 1633 sub ProcessIHL($$$) 1015 1634 { 1016 my ($e xifTool, $dirInfo, $tagTablePtr) = @_;1635 my ($et, $dirInfo, $tagTablePtr) = @_; 1017 1636 my $dataPt = $$dirInfo{DataPt}; 1018 1637 my $dataPos = $$dirInfo{DataPos}; … … 1021 1640 my $dirEnd = $pos + $dirLen; 1022 1641 1023 $e xifTool->VerboseDir('VRD IHL', 0, $dirLen);1642 $et->VerboseDir('VRD IHL', 0, $dirLen); 1024 1643 1025 1644 SetByteOrder('II'); # (make up your mind, Canon!) … … 1027 1646 my $hdr = substr($$dataPt, $pos, 48); 1028 1647 unless ($hdr =~ /^IHL Created Optional Item Data\0\0/) { 1029 $e xifTool->Warn('Possibly corrupted VRD IHL data');1648 $et->Warn('Possibly corrupted VRD IHL data'); 1030 1649 last; 1031 1650 } … … 1034 1653 my $next = Get32u($dataPt, $pos + 44); # size of complete IHL record 1035 1654 if ($size > $next or $pos + 48 + $next > $dirEnd) { 1036 $e xifTool->Warn(sprintf('Bad size for VRD IHL tag 0x%.4x', $tag));1655 $et->Warn(sprintf('Bad size for VRD IHL tag 0x%.4x', $tag)); 1037 1656 last; 1038 1657 } 1039 1658 $pos += 48; 1040 $e xifTool->HandleTag($tagTablePtr, $tag, substr($$dataPt, $pos, $size),1659 $et->HandleTag($tagTablePtr, $tag, substr($$dataPt, $pos, $size), 1041 1660 DataPt => $dataPt, 1042 1661 DataPos => $dataPos, … … 1047 1666 } 1048 1667 return 1; 1049 } 1050 1668 } 1669 1051 1670 #------------------------------------------------------------------------------ 1052 1671 # Process VRD IHL EXIF data … … 1055 1674 sub ProcessIHLExif($$$) 1056 1675 { 1057 my ($e xifTool, $dirInfo, $tagTablePtr) = @_;1058 $$e xifTool{DOC_NUM} = 1;1676 my ($et, $dirInfo, $tagTablePtr) = @_; 1677 $$et{DOC_NUM} = 1; 1059 1678 # the IHL-edited maker notes may look messed up, but the offsets should be OK 1060 my $oldFix = $e xifTool->Options(FixBase => 0);1061 my $rtnVal = $e xifTool->ProcessTIFF($dirInfo, $tagTablePtr);1062 $e xifTool->Options(FixBase => $oldFix);1063 delete $$e xifTool{DOC_NUM};1679 my $oldFix = $et->Options(FixBase => 0); 1680 my $rtnVal = $et->ProcessTIFF($dirInfo, $tagTablePtr); 1681 $et->Options(FixBase => $oldFix); 1682 delete $$et{DOC_NUM}; 1064 1683 return $rtnVal; 1684 } 1685 1686 #------------------------------------------------------------------------------ 1687 # Wrap DR4 data with the VRD header/footer and edit record 1688 # Inputs: 0) DR4 record 1689 # Returns: VRD[Edit[DR4]] data 1690 sub WrapDR4($) 1691 { 1692 my $val = shift; 1693 my $n = length $val; 1694 my $oldOrder = GetByteOrder(); 1695 SetByteOrder('MM'); 1696 $val = $blankHeader . "\xff\xff\0\xf7" . Set32u($n+8) . Set32u($n) . 1697 $val . "\0\0\0\0" . $blankFooter; 1698 # update the new VRD length in the header/footer 1699 Set32u($n + 16, \$val, 0x18); # (extra 16 bytes for the edit record wrapper) 1700 Set32u($n + 16, \$val, length($val) - 0x2c); 1701 SetByteOrder($oldOrder); 1702 return $val; 1703 } 1704 1705 #------------------------------------------------------------------------------ 1706 # Read/Write DPP version 4 edit data or DR4 file 1707 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 1708 # Returns: 1709 # Reading from memory (not RAF and not IsWriting): 1 on success 1710 # Editing from memory (not RAF and IsWriting): modified edit data, or undef if nothing changed 1711 # Reading file (RAF and not OutFile): 1 if a valid DR4 file, 0 if not 1712 # Writing file (RAF and OutFile): 1 if valid DR4 file, 0 if not, -1 on write error 1713 # (serves me right for not having a consistent interface for the various modes of operation) 1714 sub ProcessDR4($$;$) 1715 { 1716 my ($et, $dirInfo, $tagTablePtr) = @_; 1717 $et or return 1; # allow dummy access 1718 my $dataPt = $$dirInfo{DataPt}; 1719 my $raf = $$dirInfo{RAF}; 1720 my $outfile = $$dirInfo{OutFile}; 1721 my $isWriting = $outfile || $$dirInfo{IsWriting}; 1722 my $dataPos = $$dirInfo{DataPos} || 0; 1723 my $verbose = $et->Options('Verbose'); 1724 my $unknown = $et->Options('Unknown'); 1725 my ($pos, $dirLen, $numEntries, $err, $newTags); 1726 1727 # write CanonDR4 as a block if specified 1728 if ($isWriting) { 1729 my $nvHash; 1730 my $newVal = $et->GetNewValue('CanonDR4', \$nvHash); 1731 if ($newVal) { 1732 $et->VPrint(0, " Writing CanonDR4 as a block\n"); 1733 $$et{DidCanonVRD} = 1; # set flag so we don't add this twice 1734 ++$$et{CHANGED}; 1735 if ($outfile) { 1736 Write($$dirInfo{OutFile}, $newVal) or return -1; 1737 return 1; 1738 } else { 1739 return $newVal; 1740 } 1741 } elsif (not $dataPt and ($nvHash or $$et{DEL_GROUP}{CanonVRD})) { 1742 $et->Error("Can't delete all CanonDR4 information from a DR4 file"); 1743 return 1; 1744 } 1745 } 1746 if ($dataPt) { 1747 $pos = $$dirInfo{DirStart} || 0; 1748 $dirLen = $$dirInfo{DirLen} || length($$dataPt) - $pos; 1749 } else { 1750 # load DR4 file into memory 1751 my $buff; 1752 $raf->Read($buff, 8) == 8 and $buff eq "IIII\x04\0\x04\0" or return 0; 1753 $et->SetFileType(); 1754 $raf->Seek(0, 2) or return $err = 1; 1755 $dirLen = $raf->Tell(); 1756 $raf->Seek(0, 0) or return $err = 1; 1757 $raf->Read($buff, $dirLen) == $dirLen or $err = 1; 1758 $err and $et->Warn('Error reading DR4 file'), return 1; 1759 $tagTablePtr = GetTagTable('Image::ExifTool::CanonVRD::DR4'); 1760 $dataPt = \$buff; 1761 $pos = 0; 1762 } 1763 my $dirEnd = $pos + $dirLen; 1764 1765 if (($$et{TAGS_FROM_FILE} and 1766 not $$et{EXCL_TAG_LOOKUP}{canondr4}) or $$et{REQ_TAG_LOOKUP}{canondr4}) 1767 { 1768 # extract CanonDR4 block if copying tags, or if requested 1769 $et->FoundTag('CanonDR4', substr($$dataPt, $pos, $dirLen)); 1770 } 1771 1772 # version 4 header is 32 bytes (int32u[8]) 1773 if ($dirLen < 32) { 1774 $err = 1; 1775 } else { 1776 SetByteOrder(substr($$dataPt, $pos, 2)) or $err = 1; 1777 # process the DR4 header 1778 my %hdrInfo = ( 1779 DataPt => $dataPt, 1780 DirStart => $pos, 1781 DirLen => 32, 1782 DirName => 'DR4Header', 1783 ); 1784 my $hdrTable = GetTagTable('Image::ExifTool::CanonVRD::DR4Header'); 1785 if ($outfile) { 1786 my $hdr = $et->WriteDirectory(\%hdrInfo, $hdrTable); 1787 substr($$dataPt, $pos, 32) = $hdr if $hdr and length $hdr == 32; 1788 } else { 1789 $et->VerboseDir('DR4Header', undef, 32); 1790 $et->ProcessDirectory(\%hdrInfo, $hdrTable); 1791 } 1792 # number of entries in the DR4 directory 1793 $numEntries = Get32u($dataPt, $pos + 28); 1794 $err = 1 if $dirLen < 36 + 28 * $numEntries; 1795 } 1796 $err and $et->Warn('Invalid DR4 directory'), return $outfile ? undef : 0; 1797 1798 if ($outfile) { 1799 $newTags = $et->GetNewTagInfoHash($tagTablePtr); 1800 } else { 1801 $et->VerboseDir('DR4', $numEntries, $dirLen); 1802 } 1803 1804 my $index; 1805 for ($index=0; $index<$numEntries; ++$index) { 1806 my ($val, @flg, $i); 1807 my $entry = $pos + 36 + 28 * $index; 1808 last if $entry + 28 > $dirEnd; 1809 my $tag = Get32u($dataPt, $entry); 1810 my $fmt = Get32u($dataPt, $entry + 4); 1811 $flg[0] = Get32u($dataPt, $entry + 8); 1812 $flg[1] = Get32u($dataPt, $entry + 12); 1813 $flg[2] = Get32u($dataPt, $entry + 16); 1814 my $off = Get32u($dataPt, $entry + 20) + $pos; 1815 my $len = Get32u($dataPt, $entry + 24); 1816 next if $off + $len >= $dirEnd; 1817 my $format = $vrdFormat{$fmt}; 1818 if (not $format) { 1819 $val = unpack 'H*', substr($$dataPt, $off, $len); 1820 $format = 'undef'; 1821 } elsif ($format eq 'double' and $len == 8) { 1822 # avoid teeny weeny values 1823 $val = ReadValue($dataPt, $off, $format, undef, $len); 1824 $val = 0 if abs($val) < 1e-100; 1825 } 1826 if ($outfile) { 1827 # write (binary data) subdirectory if it exists 1828 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); 1829 if ($tagInfo and $$tagInfo{SubDirectory}) { 1830 my %subdirInfo = ( 1831 DataPt => $dataPt, 1832 DirStart => $off, 1833 DirLen => $len, 1834 DirName => $$tagInfo{Name}, 1835 ); 1836 my $subTablePtr = GetTagTable($$tagInfo{SubDirectory}{TagTable}); 1837 my $saveChanged = $$et{CHANGED}; 1838 my $dat = $et->WriteDirectory(\%subdirInfo, $subTablePtr); 1839 if (defined $dat and length($dat) == $len) { 1840 substr($$dataPt, $off, $len) = $dat; 1841 } else { 1842 $$et{CHANGED} = $saveChanged; # didn't change anything after all 1843 } 1844 } else { 1845 # loop through main tag and flags (don't yet consider flag 2) 1846 for ($i=-1; $i<2; ++$i) { 1847 $tagInfo = $$newTags{$i>=0 ? sprintf('0x%x.%d',$tag,$i) : $tag}; 1848 next unless $tagInfo; 1849 if ($i >= 0) { 1850 $off = $entry + 8 + 4 * $i; 1851 $format = 'int32u'; 1852 $len = 4; 1853 undef $val; 1854 } 1855 $val = ReadValue($dataPt, $off, $format, undef, $len) unless defined $val; 1856 my $nvHash; 1857 my $newVal = $et->GetNewValue($tagInfo, \$nvHash); 1858 if ($et->IsOverwriting($nvHash, $val) and defined $newVal) { 1859 my $count = int($len / Image::ExifTool::FormatSize($format)); 1860 my $rtnVal = WriteValue($newVal, $format, $count, $dataPt, $off); 1861 if (defined $rtnVal) { 1862 $et->VerboseValue("- CanonVRD:$$tagInfo{Name}", $val); 1863 $et->VerboseValue("+ CanonVRD:$$tagInfo{Name}", $newVal); 1864 ++$$et{CHANGED}; 1865 } 1866 } 1867 } 1868 } 1869 next; 1870 } 1871 $et->HandleTag($tagTablePtr, $tag, $val, 1872 DataPt => $dataPt, 1873 DataPos => $dataPos, 1874 Start => $off, 1875 Size => $len, 1876 Index => $index, 1877 Format => $format, 1878 # $flg[0] is on/off flag 1879 # $flg[1] "is default" flag? 1880 # $flg[2] changed to 0 when some unsharp mask settings were changed 1881 Extra => ", fmt=$fmt flags=" . join(',', @flg), 1882 ); 1883 foreach $i (0..2) { 1884 my $flagID = sprintf('0x%x.%d', $tag, $i); 1885 $et->HandleTag($tagTablePtr, $flagID, $flg[$i]) if $$tagTablePtr{$flagID}; 1886 } 1887 } 1888 return 1 unless $isWriting; 1889 return substr($$dataPt, $pos, $dirLen) unless $raf; 1890 return 1 if Write($outfile, substr($$dataPt, $pos, $dirLen)); 1891 return -1; 1065 1892 } 1066 1893 … … 1071 1898 sub ProcessVRD($$) 1072 1899 { 1073 my ($e xifTool, $dirInfo) = @_;1900 my ($et, $dirInfo) = @_; 1074 1901 my $raf = $$dirInfo{RAF}; 1075 1902 my $buff; … … 1077 1904 1078 1905 # initialize write directories if necessary 1079 $e xifTool->InitWriteDirs(\%vrdMap, 'XMP') if $$dirInfo{OutFile};1906 $et->InitWriteDirs(\%vrdMap, 'XMP') if $$dirInfo{OutFile}; 1080 1907 1081 1908 if (not $num and $$dirInfo{OutFile}) { 1082 1909 # create new VRD file from scratch 1083 my $newVal = $e xifTool->GetNewValues('CanonVRD');1910 my $newVal = $et->GetNewValue('CanonVRD'); 1084 1911 if ($newVal) { 1085 $e xifTool->VPrint(0, " Writing CanonVRD as a block\n");1912 $et->VPrint(0, " Writing CanonVRD as a block\n"); 1086 1913 Write($$dirInfo{OutFile}, $newVal) or return -1; 1087 ++$exifTool->{CHANGED}; 1914 $$et{DidCanonVRD} = 1; 1915 ++$$et{CHANGED}; 1088 1916 } else { 1089 1917 # allow VRD to be created from individual tags 1090 if ($$e xifTool{ADD_DIRS}{CanonVRD}) {1918 if ($$et{ADD_DIRS}{CanonVRD}) { 1091 1919 my $newVal = ''; 1092 if (ProcessCanonVRD($e xifTool, { OutFile => \$newVal }) > 0) {1920 if (ProcessCanonVRD($et, { OutFile => \$newVal }) > 0) { 1093 1921 Write($$dirInfo{OutFile}, $newVal) or return -1; 1094 ++$ exifTool->{CHANGED};1922 ++$$et{CHANGED}; 1095 1923 return 1; 1096 1924 } 1097 1925 } 1098 $e xifTool->Error('No CanonVRD information to write');1926 $et->Error('No CanonVRD information to write'); 1099 1927 } 1100 1928 } else { 1101 1929 $num == 0x1c or return 0; 1102 1930 $buff =~ /^CANON OPTIONAL DATA\0/ or return 0; 1103 $e xifTool->SetFileType();1931 $et->SetFileType(); 1104 1932 $$dirInfo{DirName} = 'CanonVRD'; # set directory name for verbose output 1105 my $result = ProcessCanonVRD($e xifTool, $dirInfo);1933 my $result = ProcessCanonVRD($et, $dirInfo); 1106 1934 return $result if $result < 0; 1107 $result or $e xifTool->Warn('Format error in VRD file');1935 $result or $et->Warn('Format error in VRD file'); 1108 1936 } 1109 1937 return 1; … … 1117 1945 sub WriteCanonVRD($$;$) 1118 1946 { 1119 my ($exifTool, $dirInfo, $tagTablePtr) = @_; 1120 $exifTool or return 1; # allow dummy access 1121 my $nvHash = $exifTool->GetNewValueHash($Image::ExifTool::Extra{CanonVRD}); 1122 return undef unless Image::ExifTool::IsOverwriting($nvHash); 1123 my $val = Image::ExifTool::GetNewValues($nvHash); 1947 my ($et, $dirInfo, $tagTablePtr) = @_; 1948 $et or return 1; # allow dummy access 1949 my $nvHash = $et->GetNewValueHash($Image::ExifTool::Extra{CanonVRD}); 1950 my $val = $et->GetNewValue($nvHash); 1124 1951 $val = '' unless defined $val; 1125 ++$exifTool->{CHANGED}; 1952 return undef unless $et->IsOverwriting($nvHash, $val); 1953 ++$$et{CHANGED}; 1126 1954 return $val; 1127 1955 } 1128 1956 1129 1957 #------------------------------------------------------------------------------ 1130 # Read/write CanonVRD information 1958 # Write DR4-type CanonVRD edit record 1959 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 1960 # Returns: VRD data block (may be empty if deleted, of undef on error) 1961 sub WriteCanonDR4($$;$) 1962 { 1963 my ($et, $dirInfo, $tagTablePtr) = @_; 1964 $et or return 1; # allow dummy access 1965 my $nvHash = $et->GetNewValueHash($Image::ExifTool::Extra{CanonDR4}); 1966 my $val = $et->GetNewValue($nvHash); 1967 if (defined $val) { 1968 return undef unless $et->IsOverwriting($nvHash, $val); 1969 $et->VPrint(0, " Writing CanonDR4 as a block\n"); 1970 ++$$et{CHANGED}; 1971 return WrapDR4($val); 1972 } 1973 my $buff = ''; 1974 $$dirInfo{OutFile} = \$buff; 1975 return $buff if ProcessCanonVRD($et, $dirInfo, $tagTablePtr) > 0; 1976 return undef; 1977 } 1978 1979 #------------------------------------------------------------------------------ 1980 # Read/write CanonVRD information (from VRD file or VRD trailer) 1131 1981 # Inputs: 0) ExifTool object reference, 1) dirInfo reference 1132 1982 # Returns: 1 on success, 0 not valid VRD, or -1 error writing 1133 1983 # - updates DataPos to point to start of CanonVRD information 1134 # - updates DirLen to trailer length1984 # - updates DirLen to existing trailer length 1135 1985 sub ProcessCanonVRD($$;$) 1136 1986 { 1137 my ($e xifTool, $dirInfo, $tagTablePtr) = @_;1987 my ($et, $dirInfo, $tagTablePtr) = @_; 1138 1988 my $raf = $$dirInfo{RAF}; 1139 1989 my $offset = $$dirInfo{Offset} || 0; 1140 1990 my $outfile = $$dirInfo{OutFile}; 1141 my $verbose = $exifTool->Options('Verbose'); 1142 my $out = $exifTool->Options('TextOut'); 1143 my ($buff, $footer, $header, $created, $err); 1144 my ($blockLen, $blockType, $size, %didDir); 1145 1146 if (not $raf) { 1147 my $vrdPt = $$dirInfo{DataPt}; 1148 unless ($vrdPt) { 1991 my $dataPt = $$dirInfo{DataPt}; 1992 my $verbose = $et->Options('Verbose'); 1993 my $out = $et->Options('TextOut'); 1994 my ($buff, $created, $err, $blockLen, $blockType, %didDir, $fromFile); 1995 # 1996 # The CanonVRD trailer has a 0x1c-byte header and a 0x40-byte footer, 1997 # each beginning with "CANON OPTIONAL DATA\0" and containing an int32u 1998 # giving the size of the contained data (at byte 0x18 and 0x14 respectively) 1999 # 2000 if ($raf) { 2001 $fromFile = 1; 2002 } else { 2003 unless ($dataPt) { 1149 2004 return 1 unless $outfile; 1150 2005 # create blank VRD data from scratch 1151 my $blank = "CANON OPTIONAL DATA\0\0\x01\0\0\0\0\0\0" . 1152 "CANON OPTIONAL DATA\0" . ("\0" x 42) . "\xff\xd9"; 1153 $vrdPt = \$blank; 1154 $verbose and printf $out " Creating CanonVRD trailer\n"; 2006 my $blank = $blankHeader . $blankFooter; 2007 $dataPt = \$blank; 2008 $verbose and print $out " Creating CanonVRD trailer\n"; 1155 2009 $created = 1; 1156 2010 } 1157 $raf = new File::RandomAccess($ vrdPt);2011 $raf = new File::RandomAccess($dataPt); 1158 2012 } 1159 # read and validate the trailer footer 1160 $raf->Seek(-64-$offset, 2) or return 0; 1161 $raf->Read($footer, 64) == 64 or return 0; 1162 $footer =~ /^CANON OPTIONAL DATA\0(.{4})/s or return 0; 1163 $size = unpack('N', $1); 1164 1165 # read and validate the header too 1166 # (header is 0x1c bytes and footer is 0x40 bytes) 1167 unless (($size & 0x80000000) == 0 and 1168 $raf->Seek(-$size-0x5c, 1) and 1169 $raf->Read($header, 0x1c) == 0x1c and 1170 $header =~ /^CANON OPTIONAL DATA\0/ and 1171 $raf->Read($buff, $size) == $size) 2013 # read and validate the footer 2014 $raf->Seek(-0x40-$offset, 2) or return 0; 2015 $raf->Read($buff, 0x40) == 0x40 or return 0; 2016 $buff =~ /^CANON OPTIONAL DATA\0(.{4})/s or return 0; 2017 my $dirLen = unpack('N', $1) + 0x5c; # size including header+footer 2018 2019 # read and validate the header 2020 unless ($dirLen < 0x80000000 and 2021 $raf->Seek(-$dirLen, 1) and 2022 $raf->Read($buff, 0x1c) == 0x1c and 2023 $buff =~ /^CANON OPTIONAL DATA\0/ and 2024 $raf->Seek(-0x1c, 1)) 1172 2025 { 1173 $e xifTool->Warn('Bad CanonVRD trailer');2026 $et->Warn('Bad CanonVRD trailer'); 1174 2027 return 0; 1175 2028 } 1176 # extract CanonVRD block if Binary option set, or if requested 1177 if ($exifTool->{OPTIONS}->{Binary} or $exifTool->{REQ_TAG_LOOKUP}->{canonvrd}) { 1178 $exifTool->FoundTag('CanonVRD', $header . $buff . $footer); 2029 # set variables returned in dirInfo hash 2030 $$dirInfo{DataPos} = $raf->Tell(); 2031 $$dirInfo{DirLen} = $dirLen; 2032 2033 if ($outfile and ref $outfile eq 'SCALAR' and not length $$outfile) { 2034 # write directly to outfile to avoid duplicating data in memory 2035 $$outfile = $$dataPt unless $fromFile; 2036 # TRICKY! -- copy to outfile memory buffer and edit in place 2037 # (so we must disable all Write() calls for this case) 2038 $dataPt = $outfile; 1179 2039 } 1180 # set variables returned in dirInfo hash 1181 $$dirInfo{DataPos} = $raf->Tell() - $size - 0x1c; 1182 $$dirInfo{DirLen} = $size + 0x5c; 2040 if ($fromFile or $$dirInfo{DirStart}) { 2041 $dataPt = \$buff unless $dataPt; 2042 # read VRD data into memory if necessary 2043 unless ($raf->Read($$dataPt, $dirLen) == $dirLen) { 2044 $$dataPt = '' if $outfile and $outfile eq $dataPt; 2045 $et->Warn('Error reading CanonVRD data'); 2046 return 0; 2047 } 2048 } 2049 # exit quickly if writing and no CanonVRD tags are being edited 2050 if ($outfile and not exists $$et{EDIT_DIRS}{CanonVRD}) { 2051 print $out "$$et{INDENT} [nothing changed]\n" if $verbose; 2052 return 1 if $outfile eq $dataPt; 2053 return Write($outfile, $$dataPt) ? 1 : -1; 2054 } 2055 2056 my $vrdType = 'VRD'; 1183 2057 1184 2058 if ($outfile) { 1185 $verbose and not $created and print f$out " Rewriting CanonVRD trailer\n";2059 $verbose and not $created and print $out " Rewriting CanonVRD trailer\n"; 1186 2060 # delete CanonVRD information if specified 1187 if ($exifTool->{DEL_GROUP}->{CanonVRD} or $exifTool->{DEL_GROUP}->{Trailer} or 1188 # also delete if writing as a block (will get added back again later) 1189 $exifTool->{NEW_VALUE}->{$Image::ExifTool::Extra{CanonVRD}}) 1190 { 1191 if ($exifTool->{FILE_TYPE} eq 'VRD') { 1192 my $newVal = $exifTool->GetNewValues('CanonVRD'); 2061 my $doDel = $$et{DEL_GROUP}{CanonVRD}; 2062 unless ($doDel) { 2063 $doDel = 1 if $$et{DEL_GROUP}{Trailer} and $$et{FILE_TYPE} ne 'VRD'; 2064 unless ($doDel) { 2065 # also delete if writing as a block (will get added back again later) 2066 if ($$et{NEW_VALUE}{$Image::ExifTool::Extra{CanonVRD}}) { 2067 # delete if this isn't version 4 2068 $doDel = 1 unless $$dataPt =~ /^.{28}\xff\xff\0\xf7/s; 2069 } 2070 if ($$et{NEW_VALUE}{$Image::ExifTool::Extra{CanonDR4}} and not $doDel) { 2071 # delete if this is version 4 2072 $doDel = 1 if $$dataPt =~ /^.{28}\xff\xff\0\xf7/s; 2073 } 2074 } 2075 } 2076 if ($doDel) { 2077 if ($$et{FILE_TYPE} eq 'VRD') { 2078 my $newVal = $et->GetNewValue('CanonVRD'); 1193 2079 if ($newVal) { 1194 $verbose and printf $out " Writing CanonVRD as a block\n"; 1195 Write($outfile, $newVal) or return -1; 1196 ++$exifTool->{CHANGED}; 2080 $verbose and print $out " Writing CanonVRD as a block\n"; 2081 if ($outfile eq $dataPt) { 2082 $$outfile = $newVal; 2083 } else { 2084 Write($outfile, $newVal) or return -1; 2085 } 2086 $$et{DidCanonVRD} = 1; 2087 ++$$et{CHANGED}; 1197 2088 } else { 1198 $e xifTool->Error("Can't delete all CanonVRD information from a VRD file");2089 $et->Error("Can't delete all CanonVRD information from a VRD file"); 1199 2090 } 1200 2091 } else { 1201 $verbose and printf $out " Deleting CanonVRD trailer\n"; 1202 ++$exifTool->{CHANGED}; 2092 $verbose and print $out " Deleting CanonVRD trailer\n"; 2093 $$outfile = '' if $outfile eq $dataPt; 2094 ++$$et{CHANGED}; 1203 2095 } 1204 2096 return 1; 1205 2097 } 1206 2098 # write now and return if CanonVRD was set as a block 1207 my $val = $exifTool->GetNewValues('CanonVRD'); 2099 my $val = $et->GetNewValue('CanonVRD'); 2100 unless ($val) { 2101 $val = $et->GetNewValue('CanonDR4'); 2102 $vrdType = 'DR4' if $val; 2103 } 1208 2104 if ($val) { 1209 $verbose and print $out " Writing CanonVRD as a block\n"; 1210 Write($outfile, $val) or return -1; 1211 ++$exifTool->{CHANGED}; 2105 $verbose and print $out " Writing Canon$vrdType as a block\n"; 2106 # must wrap DR4 data with the VRD header/footer and edit record 2107 $val = WrapDR4($val) if $vrdType eq 'DR4'; 2108 if ($outfile eq $dataPt) { 2109 $$outfile = $val; 2110 } else { 2111 Write($outfile, $val) or return -1; 2112 } 2113 $$et{DidCanonVRD} = 1; 2114 ++$$et{CHANGED}; 1212 2115 return 1; 1213 2116 } 1214 } elsif ($verbose or $ exifTool->{HTML_DUMP}) {1215 $e xifTool->DumpTrailer($dirInfo) if $$dirInfo{RAF};2117 } elsif ($verbose or $$et{HTML_DUMP}) { 2118 $et->DumpTrailer($dirInfo) if $$dirInfo{RAF}; 1216 2119 } 1217 2120 … … 1219 2122 1220 2123 # validate VRD trailer and get position and length of edit record 1221 SetByteOrder('MM'); 1222 my $pos = 0; 1223 my $vrdPos = $$dirInfo{DataPos} + length($header); 1224 my $dataPt = \$buff; 2124 SetByteOrder('MM'); # VRD header/footer is big-endian 2125 my $pos = 0x1c; # start at end of header 1225 2126 1226 2127 # loop through the VRD blocks 1227 2128 for (;;) { 1228 if ($pos + 8 > $size) { 1229 last if $pos == $size; 1230 $blockLen = $size; # mark as invalid 2129 my $end = $dirLen - 0x40; # end of last VRD block (and start of footer) 2130 if ($pos + 8 > $end) { 2131 last if $pos == $end; 2132 $blockLen = $end; # mark as invalid 1231 2133 } else { 1232 2134 $blockType = Get32u($dataPt, $pos); 1233 2135 $blockLen = Get32u($dataPt, $pos + 4); 1234 2136 } 1235 $pos += 8; # move to start of block 1236 if ($pos + $blockLen > $size) { 1237 $exifTool->Warn('Possibly corrupt CanonVRD block'); 2137 $vrdType = 'DR4' if $blockType == 0xffff00f7; 2138 $pos += 8; # move to start of block 2139 if ($pos + $blockLen > $end) { 2140 $et->Warn('Possibly corrupt CanonVRD block'); 1238 2141 last; 1239 2142 } 1240 2143 if ($verbose > 1 and not $outfile) { 1241 2144 printf $out " CanonVRD block 0x%.8x ($blockLen bytes at offset 0x%x)\n", 1242 $blockType, $pos + $vrdPos; 1243 if ($verbose > 2) { 1244 my %parms = ( 1245 Start => $pos, 1246 Addr => $pos + $vrdPos, 1247 Out => $out, 1248 Prefix => $$exifTool{INDENT}, 1249 ); 1250 $parms{MaxLen} = $verbose == 3 ? 96 : 2048 if $verbose < 5; 1251 Image::ExifTool::HexDump($dataPt, $blockLen, %parms); 1252 } 2145 $blockType, $pos + $$dirInfo{DataPos}; 2146 $et->VerboseDump($dataPt, Len => $blockLen, Start => $pos, Addr => $pos + $$dirInfo{DataPos}); 1253 2147 } 1254 2148 my $tagInfo = $$tagTablePtr{$blockType}; 1255 2149 unless ($tagInfo) { 1256 unless ($e xifTool->Options('Unknown')) {2150 unless ($et->Options('Unknown')) { 1257 2151 $pos += $blockLen; # step to next block 1258 2152 next; … … 1266 2160 Binary => 1, 1267 2161 }; 1268 Image::ExifTool::AddTagToTable($tagTablePtr, $blockType, $tagInfo);2162 AddTagToTable($tagTablePtr, $blockType, $tagInfo); 1269 2163 } 1270 2164 if ($$tagInfo{SubDirectory}) { … … 1273 2167 DataPt => $dataPt, 1274 2168 DataLen => length $$dataPt, 1275 DataPos => $ vrdPos,2169 DataPos => $$dirInfo{DataPos}, 1276 2170 DirStart => $pos, 1277 2171 DirLen => $blockLen, … … 1283 2177 # set flag indicating we did this directory 1284 2178 $didDir{$$tagInfo{Name}} = 1; 1285 my $dat;1286 if ($$e xifTool{NEW_VALUE}{$tagInfo}) {2179 my ($dat, $diff); 2180 if ($$et{NEW_VALUE}{$tagInfo}) { 1287 2181 # write as a block 1288 $e xifTool->VPrint(0, "Writing $$tagInfo{Name} as a block\n");1289 $dat = $e xifTool->GetNewValues($tagInfo);2182 $et->VPrint(0, "Writing $$tagInfo{Name} as a block\n"); 2183 $dat = $et->GetNewValue($tagInfo); 1290 2184 $dat = '' unless defined $dat; 1291 ++$$e xifTool{CHANGED};2185 ++$$et{CHANGED}; 1292 2186 } else { 1293 $dat = $e xifTool->WriteDirectory(\%subdirInfo, $subTablePtr);2187 $dat = $et->WriteDirectory(\%subdirInfo, $subTablePtr); 1294 2188 } 1295 2189 # update data with new directory 1296 2190 if (defined $dat) { 1297 my $buf2; 1298 if (length $dat or $$exifTool{FILE_TYPE} !~ /^(CRW|VRD)$/) { 2191 if (length $dat or $$et{FILE_TYPE} !~ /^(CRW|VRD)$/) { 1299 2192 # replace with new block (updating the block length word) 1300 $buf2 = substr($$dataPt, 0, $pos - 4) .Set32u(length $dat) . $dat;2193 substr($$dataPt, $pos-4, $blockLen+4) = Set32u(length $dat) . $dat; 1301 2194 } else { 1302 2195 # remove block totally (CRW/VRD files only) 1303 $buf2 = substr($$dataPt, 0, $pos - 8);2196 substr($$dataPt, $pos-8, $blockLen+8) = ''; 1304 2197 } 1305 my $oldBlockEnd = $pos + $blockLen; 1306 $pos = length $$dataPt; # set to start of next block 1307 $buf2 .= substr($$dataPt, $oldBlockEnd); 1308 undef $$dataPt; # free the memory 1309 $dataPt = \$buf2; 1310 # update the new VRD length in the header/footer 1311 Set32u(length($buf2), \$header, 0x18); 1312 Set32u(length($buf2), \$footer, 0x14); 1313 next; 2198 # make necessary adjustments if block changes length 2199 if (($diff = length($$dataPt) - $dirLen) != 0) { 2200 $pos += $diff; 2201 $dirLen += $diff; 2202 # update the new VRD length in the header/footer 2203 Set32u($dirLen - 0x5c, $dataPt, 0x18); 2204 Set32u($dirLen - 0x5c, $dataPt, $dirLen - 0x2c); 2205 } 1314 2206 } 1315 2207 } else { 1316 2208 # extract as a block if requested 1317 $e xifTool->ProcessDirectory(\%subdirInfo, $subTablePtr);2209 $et->ProcessDirectory(\%subdirInfo, $subTablePtr); 1318 2210 } 1319 2211 } else { 1320 $e xifTool->HandleTag($tagTablePtr, $blockType, substr($$dataPt, $pos, $blockLen));2212 $et->HandleTag($tagTablePtr, $blockType, substr($$dataPt, $pos, $blockLen)); 1321 2213 } 1322 2214 $pos += $blockLen; # step to next block … … 1324 2216 if ($outfile) { 1325 2217 # create XMP block if necessary (CRW/VRD files only) 1326 if ($$e xifTool{ADD_DIRS}{CanonVRD} and not $didDir{XMP}) {2218 if ($$et{ADD_DIRS}{CanonVRD} and not $didDir{XMP}) { 1327 2219 my $subTablePtr = GetTagTable('Image::ExifTool::XMP::Main'); 1328 my $dat = $e xifTool->WriteDirectory({ Parent => 'CanonVRD' }, $subTablePtr);2220 my $dat = $et->WriteDirectory({ Parent => 'CanonVRD' }, $subTablePtr); 1329 2221 if ($dat) { 1330 $$dataPt .= Set32u(0xffff00f6) . Set32u(length $dat) . $dat; 2222 my $blockLen = length $dat; 2223 substr($$dataPt, -0x40, 0) = Set32u(0xffff00f6) . Set32u(length $dat) . $dat; 2224 $dirLen = length $$dataPt; 1331 2225 # update the new VRD length in the header/footer 1332 Set32u( length($$dataPt), \$header, 0x18);1333 Set32u( length($$dataPt), \$footer, 0x14);2226 Set32u($dirLen - 0x5c, $dataPt, 0x18); 2227 Set32u($dirLen - 0x5c, $dataPt, $dirLen - 0x2c); 1334 2228 } 1335 2229 } 1336 2230 # write CanonVRD trailer unless it is empty 1337 2231 if (length $$dataPt) { 1338 Write($outfile, $ header, $$dataPt, $footer) or $err = 1;2232 Write($outfile, $$dataPt) or $err = 1 unless $outfile eq $dataPt; 1339 2233 } else { 1340 $verbose and printf $out " Deleting CanonVRD trailer\n"; 1341 } 2234 $verbose and print $out " Deleting CanonVRD trailer\n"; 2235 } 2236 } elsif ($vrdType eq 'VRD' and (($$et{TAGS_FROM_FILE} and 2237 not $$et{EXCL_TAG_LOOKUP}{canonvrd}) or $$et{REQ_TAG_LOOKUP}{canonvrd})) 2238 { 2239 # extract CanonVRD block if copying tags, or if requested (and not DR4 info) 2240 $et->FoundTag('CanonVRD', $buff); 1342 2241 } 1343 undef $ $dataPt;2242 undef $buff; 1344 2243 return $err ? -1 : 1; 1345 2244 } … … 1351 2250 =head1 NAME 1352 2251 1353 Image::ExifTool::CanonVRD - Read/write Canon VRD information2252 Image::ExifTool::CanonVRD - Read/write Canon VRD and DR4 information 1354 2253 1355 2254 =head1 SYNOPSIS … … 1360 2259 1361 2260 This module contains definitions required by Image::ExifTool to read and 1362 write VRD Recipe Data information as written by the Canon Digital Photo1363 P rofessional software. This information is written to VRD files, and as a1364 trailer in JPEG, CRW, CR2 and TIFF images.2261 write VRD and DR4 Recipe Data information as written by the Canon Digital 2262 Photo Professional software. This information is written to VRD and DR4 2263 files, and as a trailer in JPEG, CRW, CR2 and TIFF images. 1365 2264 1366 2265 =head1 AUTHOR 1367 2266 1368 Copyright 2003-20 11, Phil Harvey (phil at owl.phy.queensu.ca)2267 Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com) 1369 2268 1370 2269 This library is free software; you can redistribute it and/or modify it
Note:
See TracChangeset
for help on using the changeset viewer.