- Timestamp:
- 2011-06-01T12:33:42+12:00 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone2/perllib/cpan/Image/ExifTool/WriteExif.pl
r16842 r24107 11 11 use strict; 12 12 use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber 13 % lightSource %compression %photometricInterpretation %orientation);13 %compression %photometricInterpretation %orientation); 14 14 15 15 use Image::ExifTool::Fixup; … … 30 30 0x011a => 72, # XResolution 31 31 0x011b => 72, # YResolution 32 0x0128 => 2, # Resolution unit (inches)32 0x0128 => 2, # ResolutionUnit (inches) 33 33 0x0213 => 1, # YCbCrPositioning (centered) 34 34 # 0x8769 => ????, # ExifOffset … … 38 38 0x011a => 72, # XResolution 39 39 0x011b => 72, # YResolution 40 0x0128 => 2, # Resolution unit (inches)40 0x0128 => 2, # ResolutionUnit (inches) 41 41 }, 42 42 ExifIFD => { 43 0x9000 => '02 20', # ExifVersion44 0x9101 => " \1\2\3\0",# ComponentsConfiguration43 0x9000 => '0230', # ExifVersion 44 0x9101 => "1 2 3 0",# ComponentsConfiguration 45 45 0xa000 => '0100', # FlashpixVersion 46 46 0xa001 => 0xffff, # ColorSpace (uncalibrated) 47 47 # 0xa002 => ????, # ExifImageWidth 48 # 0xa003 => ????, # ExifImage Length48 # 0xa003 => ????, # ExifImageHeight 49 49 }, 50 50 GPS => { 51 0x0000 => '2 20 0',# GPSVersionID51 0x0000 => '2 3 0 0',# GPSVersionID 52 52 }, 53 53 InteropIFD => { … … 72 72 Protected => 1, 73 73 Writable => 'undef', 74 Mandatory => 1, 74 75 WriteGroup => 'InteropIFD', 75 76 }, … … 93 94 WriteGroup => 'IFD0', 94 95 }, 95 0x0101 => { # ImageHeig th96 0x0101 => { # ImageHeight 96 97 Protected => 1, 97 98 Writable => 'int32u', … … 108 109 Writable => 'int16u', 109 110 WriteGroup => 'IFD0', 111 Mandatory => 1, 110 112 }, 111 113 0x0106 => { # PhotometricInterpretation … … 175 177 Writable => 'rational64u', 176 178 WriteGroup => 'IFD0', 179 Mandatory => 1, 177 180 }, 178 181 0x011b => { # YResolution 179 182 Writable => 'rational64u', 180 183 WriteGroup => 'IFD0', 184 Mandatory => 1, 181 185 }, 182 186 0x011c => { # PlanarConfiguration … … 204 208 Writable => 'int16u', 205 209 WriteGroup => 'IFD0', 210 Mandatory => 1, 206 211 }, 207 212 0x0129 => { # PageNumber … … 210 215 Count => 2, 211 216 }, 217 0x012d => { # TransferFunction 218 Protected => 1, 219 Writable => 'int16u', 220 WriteGroup => 'IFD0', 221 Count => 768, 222 }, 212 223 0x0131 => { # Software 213 224 Writable => 'string', … … 218 229 Shift => 'Time', 219 230 WriteGroup => 'IFD0', 220 PrintConvInv => ' Image::ExifTool::Exif::ExifDateTime($val)',231 PrintConvInv => '$self->InverseDateTime($val,0)', 221 232 }, 222 233 0x013b => { # Artist … … 286 297 Writable => 'int16u', 287 298 WriteGroup => 'IFD0', 299 Mandatory => 1, 288 300 }, 289 301 0x0214 => { # ReferenceBlackWhite … … 302 314 WriteGroup => 'InteropIFD', 303 315 }, 304 0x1002 => { # RelatedImage Length (is really the height)316 0x1002 => { # RelatedImageHeight (more commonly RelatedImageLength) 305 317 Protected => 1, 306 318 Writable => 'int16u', … … 320 332 Writable => 'string', 321 333 WriteGroup => 'IFD0', 334 RawConvInv => q{ 335 if ($val =~ /(.*?)\s*[\n\r]+\s*(.*)/s) { 336 return $1 . "\0" unless length $2; 337 # photographer copyright set to ' ' if it doesn't exist, according to spec. 338 return((length($1) ? $1 : ' ') . "\0" . $2 . "\0"); 339 } 340 return $val . "\0"; 341 }, 322 342 }, 323 343 # … … 326 346 0x829a => { # ExposureTime 327 347 Writable => 'rational64u', 328 PrintConvInv => ' eval $val',348 PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', 329 349 }, 330 350 0x829d => { # FNumber … … 332 352 PrintConvInv => '$val', 333 353 }, 334 0x83bb => { # IPTC-NAA335 # this should actually be written as 'undef' (see336 # http://www.awaresystems.be/imaging/tiff/tifftags/iptc.html),337 # but Photoshop writes it as int32u and Nikon Capture won't read338 # anything else, so we do the same thing here... Doh!339 Format => 'undef', # convert binary values as undef340 Writable => 'int32u', # but write int32u format code in IFD341 WriteGroup => 'IFD0',342 },343 354 0x8546 => { # SEMInfo 344 355 Writable => 'string', … … 347 358 0x8822 => 'int16u', # ExposureProgram 348 359 0x8824 => 'string', # SpectralSensitivity 349 0x8827 => 'int16u', # ISO 360 0x8827 => { # ISO 361 Writable => 'int16u', 362 Count => -1, 363 PrintConvInv => '$val=~tr/,//d; $val', 364 }, 350 365 0x882a => { # TimeZoneOffset 351 366 Writable => 'int16s', … … 357 372 }, 358 373 0x882b => 'int16u', # SelfTimerMode 359 0x9000 => 'undef', # ExifVersion 374 0x8830 => 'int16u', # SensitivityType 375 0x8831 => 'int32u', # StandardOutputSensitivity 376 0x8832 => 'int32u', # RecommendedExposureIndex 377 0x8833 => 'int32u', # ISOSpeed 378 0x8834 => 'int32u', # ISOSpeedLatitudeyyy 379 0x8835 => 'int32u', # ISOSpeedLatitudezzz 380 0x9000 => { # ExifVersion 381 Writable => 'undef', 382 Mandatory => 1, 383 }, 360 384 0x9003 => { # DateTimeOriginal 361 385 Writable => 'string', 362 386 Shift => 'Time', 363 PrintConvInv => ' Image::ExifTool::Exif::ExifDateTime($val)',387 PrintConvInv => '$self->InverseDateTime($val,0)', 364 388 }, 365 389 0x9004 => { # CreateDate 366 390 Writable => 'string', 367 391 Shift => 'Time', 368 PrintConvInv => ' Image::ExifTool::Exif::ExifDateTime($val)',392 PrintConvInv => '$self->InverseDateTime($val,0)', 369 393 }, 370 394 0x9101 => { # ComponentsConfiguration 395 Protected => 1, 371 396 Writable => 'undef', 372 PrintConv => '$_=$val;s/\0.*//s;tr/\x01-\x06/YXWRGB/;s/X/Cb/g;s/W/Cr/g;$_', 373 PrintConvInv => q{ 374 $_=uc($val); s/CR/W/g; s/CB/X/g; 375 return undef if /[^YXWRGB]/; 376 tr/YXWRGB/\x01-\x06/; 377 return $_ . "\0"; 378 }, 379 }, 380 0x9102 => 'rational64u',# CompressedBitsPerPixel 397 Count => 4, 398 Mandatory => 1, 399 ValueConvInv => '$val=~tr/,//d; $val', # (so we can copy from XMP with -n) 400 }, 401 0x9102 => { # CompressedBitsPerPixel 402 Protected => 1, 403 Writable => 'rational64u', 404 }, 381 405 0x9201 => { # ShutterSpeedValue 382 406 Writable => 'rational64s', 383 407 ValueConvInv => '$val>0 ? -log($val)/log(2) : -100', 384 408 # do eval to convert things like '1/100' 385 PrintConvInv => ' eval $val',409 PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', 386 410 }, 387 411 0x9202 => { # ApertureValue … … 394 418 Writable => 'rational64s', 395 419 # do eval to convert things like '+2/3' 396 PrintConvInv => ' eval $val',420 PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', 397 421 }, 398 422 0x9205 => { # MaxApertureValue … … 415 439 0x9212 => 'string', # SecurityClassification 416 440 0x9213 => 'string', # ImageHistory 417 0x9214 => { # Subject Location418 Writable => 'int16u', 419 Count => 4, # write this SubjectLocation with 4 and the other with 2values441 0x9214 => { # SubjectArea 442 Writable => 'int16u', 443 Count => -1, # 2, 3 or 4 values 420 444 }, 421 445 # 0x927c => 'undef', # MakerNotes 422 0x9286 => { # UserComment (string that starts with "ASCII\0\0\0")446 0x9286 => { # UserComment 423 447 Writable => 'undef', 424 PrintConvInv => 'Image::ExifTool::Exif::EncodeExifText($self,$val)', 425 }, 426 0x9290 => 'string', # SubSecTime 427 0x9291 => 'string', # SubSecTimeOriginal 428 0x9292 => 'string', # SubSecTimeDigitized 448 # (starts with "ASCII\0\0\0", "UNICODE\0", "JIS\0\0\0\0\0" or "\0\0\0\0\0\0\0\0") 449 RawConvInv => 'Image::ExifTool::Exif::EncodeExifText($self,$val)', 450 # SHOULD ADD SPECIAL LOGIC TO ALLOW CONDITIONAL OVERWRITE OF 451 # "UNKNOWN" VALUES FILLED WITH SPACES 452 }, 453 0x9290 => { # SubSecTime 454 Writable => 'string', 455 # extract fractional seconds from a full date/time value 456 ValueConvInv => '$val=~/^(\d+)\s*$/ ? $1 : ($val=~/\.(\d+)/ ? $1 : undef)', 457 }, 458 0x9291 => { # SubSecTimeOriginal 459 Writable => 'string', 460 ValueConvInv => '$val=~/^(\d+)\s*$/ ? $1 : ($val=~/\.(\d+)/ ? $1 : undef)', 461 }, 462 0x9292 => { # SubSecTimeDigitized 463 Writable => 'string', 464 ValueConvInv => '$val=~/^(\d+)\s*$/ ? $1 : ($val=~/\.(\d+)/ ? $1 : undef)', 465 }, 429 466 0x935c => { # ImageSourceData 430 467 Writable => 'undef', 431 468 WriteGroup => 'IFD0', 469 Protected => 1, 432 470 }, 433 471 # 0x9928 => 'undef', # Opto-ElectricConversionFactor … … 438 476 tags 0x9c9b-0x9c9f are used by Windows Explorer; special characters 439 477 in these values are converted to UTF-8 by default, or Windows Latin1 440 with the -L option. XPTitle is ignored by Windows Explorer if478 with the -L option. XPTitle is ignored by Windows Explorer if 441 479 ImageDescription exists 442 480 }, 443 ValueConvInv => '$self-> Charset2Unicode($val,"II") . "\0\0"',481 ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"', 444 482 }, 445 483 0x9c9c => { # XPComment 446 484 Writable => 'int8u', 447 485 WriteGroup => 'IFD0', 448 ValueConvInv => '$self-> Charset2Unicode($val,"II") . "\0\0"',486 ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"', 449 487 }, 450 488 0x9c9d => { # XPAuthor … … 452 490 WriteGroup => 'IFD0', 453 491 Notes => 'ignored by Windows Explorer if Artist exists', 454 ValueConvInv => '$self-> Charset2Unicode($val,"II") . "\0\0"',492 ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"', 455 493 }, 456 494 0x9c9e => { # XPKeywords 457 495 Writable => 'int8u', 458 496 WriteGroup => 'IFD0', 459 ValueConvInv => '$self-> Charset2Unicode($val,"II") . "\0\0"',497 ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"', 460 498 }, 461 499 0x9c9f => { # XPSubject 462 500 Writable => 'int8u', 463 501 WriteGroup => 'IFD0', 464 ValueConvInv => '$self->Charset2Unicode($val,"II") . "\0\0"', 465 }, 466 0xa000 => 'undef', # FlashpixVersion 467 0xa001 => 'int16u', # ColorSpace 468 0xa002 => 'int16u', # ExifImageWidth (could also be int32u) 469 0xa003 => 'int16u', # ExifImageLength (could also be int32u) 502 ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"', 503 }, 504 0xa000 => { # FlashpixVersion 505 Writable => 'undef', 506 Mandatory => 1, 507 }, 508 0xa001 => { # ColorSpace 509 Writable => 'int16u', 510 Mandatory => 1, 511 }, 512 0xa002 => { # ExifImageWidth (could also be int32u) 513 Writable => 'int16u', 514 Mandatory => 1, 515 }, 516 0xa003 => { # ExifImageHeight (could also be int32u) 517 Writable => 'int16u', 518 Mandatory => 1, 519 }, 470 520 0xa004 => 'string', # RelatedSoundFile 471 521 0xa20b => { # FlashEnergy … … 485 535 0xa300 => { # FileSource 486 536 Writable => 'undef', 487 ValueConvInv => 'chr($val)', 488 PrintConvInv => 3, 537 ValueConvInv => '($val=~/^\d+$/ and $val < 256) ? chr($val) : $val', 489 538 }, 490 539 0xa301 => { # SceneType … … 521 570 0xa40c => 'int16u', # SubjectDistanceRange 522 571 0xa420 => 'string', # ImageUniqueID 572 0xa430 => 'string', # OwnerName 573 0xa431 => 'string', # SerialNumber 574 0xa432 => { # LensInfo 575 Writable => 'rational64u', 576 Count => 4, 577 PrintConvInv => \&ConvertLensInfo, 578 }, 579 0xa433 => 'string', # LensMake 580 0xa434 => 'string', # LensModel 581 0xa435 => 'string', # LensSerialNumber 523 582 0xa500 => 'rational64u',# Gamma 524 0xc4a5 => { # PrintIM525 Writable => 'undef',526 WriteGroup => 'IFD0',527 },528 583 # 529 584 # DNG stuff (back in IFD0) … … 533 588 WriteGroup => 'IFD0', 534 589 Count => 4, 590 Protected => 1, # (confuses Apple Preview if written to a TIFF image) 591 PrintConvInv => '$val =~ tr/./ /; $val', 535 592 }, 536 593 0xc613 => { # DNGBackwardVersion … … 538 595 WriteGroup => 'IFD0', 539 596 Count => 4, 597 Protected => 1, 540 598 }, 541 599 0xc614 => { # UniqueCameraModel … … 547 605 WriteGroup => 'IFD0', 548 606 PrintConvInv => '$val', 607 }, 608 0xc619 => { # BlackLevelRepeatDim 609 Writable => 'int16u', 610 WriteGroup => 'SubIFD', 611 Count => 2, 612 Protected => 1, 613 }, 614 0xc61a => { # BlackLevel 615 Writable => 'rational64u', 616 WriteGroup => 'SubIFD', 617 Count => -1, 618 Protected => 1, 619 }, 620 0xc61d => { # WhiteLevel 621 Writable => 'int32u', 622 WriteGroup => 'SubIFD', 623 Count => -1, 624 Protected => 1, 549 625 }, 550 626 0xc61e => { # DefaultScale … … 552 628 WriteGroup => 'SubIFD', 553 629 Count => 2, 630 Protected => 1, 554 631 }, 555 632 0xc61f => { # DefaultCropOrigin … … 557 634 WriteGroup => 'SubIFD', 558 635 Count => 2, 636 Protected => 1, 559 637 }, 560 638 0xc620 => { # DefaultCropSize … … 562 640 WriteGroup => 'SubIFD', 563 641 Count => 2, 642 Protected => 1, 643 }, 644 0xc621 => { # ColorMatrix1 645 Writable => 'rational64s', 646 Count => -1, 647 WriteGroup => 'IFD0', 648 Protected => 1, 649 }, 650 0xc622 => { # ColorMatrix2 651 Writable => 'rational64s', 652 Count => -1, 653 WriteGroup => 'IFD0', 654 Protected => 1, 655 }, 656 0xc623 => { # CameraCalibration1 657 Writable => 'rational64s', 658 Count => -1, 659 WriteGroup => 'IFD0', 660 Protected => 1, 661 }, 662 0xc624 => { # CameraCalibration2 663 Writable => 'rational64s', 664 Count => -1, 665 WriteGroup => 'IFD0', 666 Protected => 1, 667 }, 668 0xc625 => { # ReductionMatrix1 669 Writable => 'rational64s', 670 Count => -1, 671 WriteGroup => 'IFD0', 672 Protected => 1, 673 }, 674 0xc626 => { # ReductionMatrix2 675 Writable => 'rational64s', 676 Count => -1, 677 WriteGroup => 'IFD0', 678 Protected => 1, 679 }, 680 0xc627 => { # AnalogBalance 681 Writable => 'rational64u', 682 Count => -1, 683 WriteGroup => 'IFD0', 684 Protected => 1, 685 }, 686 0xc628 => { # AsShotNeutral 687 Writable => 'rational64u', 688 WriteGroup => 'IFD0', 689 Count => -1, 690 Protected => 1, 564 691 }, 565 692 0xc629 => { # AsShotWhiteXY … … 567 694 WriteGroup => 'IFD0', 568 695 Count => 2, 696 Protected => 1, 569 697 }, 570 698 0xc62a => { # BaselineExposure 571 699 Writable => 'rational64s', 572 700 WriteGroup => 'IFD0', 701 Protected => 1, 573 702 }, 574 703 0xc62b => { # BaselineNoise 575 704 Writable => 'rational64u', 576 705 WriteGroup => 'IFD0', 706 Protected => 1, 577 707 }, 578 708 0xc62c => { # BaselineSharpness 579 709 Writable => 'rational64u', 580 710 WriteGroup => 'IFD0', 711 Protected => 1, 581 712 }, 582 713 0xc62d => { # BayerGreenSplit 583 714 Writable => 'int32u', 584 715 WriteGroup => 'SubIFD', 716 Protected => 1, 585 717 }, 586 718 0xc62e => { # LinearResponseLimit 587 719 Writable => 'rational64u', 588 720 WriteGroup => 'IFD0', 721 Protected => 1, 589 722 }, 590 723 0xc62f => { # CameraSerialNumber … … 596 729 WriteGroup => 'IFD0', 597 730 Count => 4, 598 PrintConvInv => '$_=$val;s/(-|mm f)/ /g;$_',731 PrintConvInv => \&ConvertLensInfo, 599 732 }, 600 733 0xc631 => { # ChromaBlurRadius 601 734 Writable => 'rational64u', 602 735 WriteGroup => 'SubIFD', 736 Protected => 1, 603 737 }, 604 738 0xc632 => { # AntiAliasStrength 605 739 Writable => 'rational64u', 606 740 WriteGroup => 'SubIFD', 741 Protected => 1, 607 742 }, 608 743 0xc633 => { # ShadowScale 609 744 Writable => 'rational64u', 610 745 WriteGroup => 'IFD0', 746 Protected => 1, 611 747 }, 612 748 0xc635 => { # MakerNoteSafety … … 617 753 Writable => 'int16u', 618 754 WriteGroup => 'IFD0', 755 Protected => 1, 619 756 }, 620 757 0xc65b => { # CalibrationIlluminant2 621 758 Writable => 'int16u', 622 759 WriteGroup => 'IFD0', 760 Protected => 1, 623 761 }, 624 762 0xc65c => { # BestQualityScale 625 763 Writable => 'rational64u', 626 764 WriteGroup => 'SubIFD', 765 Protected => 1, 627 766 }, 628 767 0xc65d => { # RawDataUniqueID … … 630 769 WriteGroup => 'IFD0', 631 770 Count => 16, 632 ValueConvInv => 'pack("H*",$val)', 771 ValueConvInv => 'pack("H*", $val)', 772 Protected => 1, 633 773 }, 634 774 0xc68b => { # OriginalRawFileName 635 775 Writable => 'string', 636 776 WriteGroup => 'IFD0', 637 }, 638 0xc68c => { # OriginalRawFileData (a writable directory) 639 Writable => 'undef', 640 WriteGroup => 'IFD0', 777 Protected => 1, 641 778 }, 642 779 0xc68d => { # ActiveArea … … 644 781 WriteGroup => 'SubIFD', 645 782 Count => 4, 783 Protected => 1, 646 784 }, 647 785 0xc68e => { # MaskedAreas … … 649 787 WriteGroup => 'SubIFD', 650 788 Count => 4, 651 },652 0xc68f => { # AsShotICCProfile653 Writable => 'undef',789 Protected => 1, 790 }, 791 0xc68f => { # AsShotICCProfile (writable directory) 654 792 WriteGroup => 'IFD0', 655 793 Protected => 1, … … 665 803 Protected => 1, 666 804 }, 667 0xc691 => { # CurrentICCProfile 805 0xc691 => { # CurrentICCProfile (writable directory) 668 806 Writable => 'undef', 669 807 WriteGroup => 'IFD0', … … 676 814 0xc692 => { # CurrentPreProfileMatrix 677 815 Writable => 'rational64s', 816 Count => -1, 817 WriteGroup => 'IFD0', 818 Protected => 1, 819 }, 820 0xc6bf => { # ColorimetricReference 821 Writable => 'int16u', 822 WriteGroup => 'IFD0', 823 Protected => 1, 824 }, 825 0xc6d2 => { # PanasonicTitle (Panasonic DMC-TZ5, not a DNG tag) 826 Writable => 'undef', 827 WriteGroup => 'IFD0', 828 ValueConvInv => '$self->Encode($val,"UTF8")', 829 }, 830 0xc6d3 => { # PanasonicTitle2 (Panasonic DMC-FS7, not a DNG tag) 831 Writable => 'undef', 832 WriteGroup => 'IFD0', 833 ValueConvInv => '$self->Encode($val,"UTF8")', 834 }, 835 0xc6f3 => { # CameraCalibrationSig 836 Writable => 'string', 837 WriteGroup => 'IFD0', 838 Protected => 1, 839 }, 840 0xc6f4 => { # ProfileCalibrationSig 841 Writable => 'string', 842 WriteGroup => 'IFD0', 843 Protected => 1, 844 }, 845 0xc6f6 => { # AsShotProfileName 846 Writable => 'string', 847 WriteGroup => 'IFD0', 848 Protected => 1, 849 }, 850 0xc6f7 => { # NoiseReductionApplied 851 Writable => 'rational64u', 852 WriteGroup => 'SubIFD', 853 Protected => 1, 854 }, 855 0xc6f8 => { # ProfileName 856 Writable => 'string', 857 WriteGroup => 'IFD0', 858 Protected => 1, 859 }, 860 0xc6f9 => { # ProfileHueSatMapDims 861 Writable => 'int32u', 862 Count => 3, 863 WriteGroup => 'IFD0', 864 Protected => 1, 865 }, 866 0xc6fa => { # ProfileHueSatMapData1 867 Writable => 'float', 868 Count => -1, 869 WriteGroup => 'IFD0', 870 Protected => 1, 871 }, 872 0xc6fb => { # ProfileHueSatMapData2 873 Writable => 'float', 874 Count => -1, 875 WriteGroup => 'IFD0', 876 Protected => 1, 877 }, 878 0xc6fc => { # ProfileToneCurve 879 Writable => 'float', 880 Count => -1, 881 WriteGroup => 'IFD0', 882 Protected => 1, 883 }, 884 0xc6fd => { # ProfileEmbedPolicy 885 Writable => 'int32u', 886 WriteGroup => 'IFD0', 887 Protected => 1, 888 }, 889 0xc6fe => { # ProfileCopyright 890 Writable => 'string', 891 WriteGroup => 'IFD0', 892 Protected => 1, 893 }, 894 0xc714 => { # ForwardMatrix1 895 Writable => 'rational64s', 896 Count => -1, 897 WriteGroup => 'IFD0', 898 Protected => 1, 899 }, 900 0xc715 => { # ForwardMatrix2 901 Writable => 'rational64s', 902 Count => -1, 903 WriteGroup => 'IFD0', 904 Protected => 1, 905 }, 906 0xc716 => { # PreviewApplicationName 907 Writable => 'string', 908 WriteGroup => 'IFD0', 909 Protected => 1, 910 }, 911 0xc717 => { # PreviewApplicationVersion 912 Writable => 'string', 913 WriteGroup => 'IFD0', 914 Protected => 1, 915 }, 916 0xc718 => { # PreviewSettingsName 917 Writable => 'string', 918 WriteGroup => 'IFD0', 919 Protected => 1, 920 }, 921 0xc719 => { # PreviewSettingsDigest 922 Writable => 'int8u', 923 WriteGroup => 'IFD0', 924 Protected => 1, 925 ValueConvInv => 'pack("H*", $val)', 926 }, 927 0xc71a => { # PreviewColorSpace 928 Writable => 'int32u', 929 WriteGroup => 'IFD0', 930 Protected => 1, 931 PrintConv => { 932 0 => 'Unknown', 933 1 => 'Gray Gamma 2.2', 934 2 => 'sRGB', 935 3 => 'Adobe RGB', 936 4 => 'ProPhoto RGB', 937 }, 938 }, 939 0xc71b => { # PreviewDateTime 940 Writable => 'string', 941 WriteGroup => 'IFD0', 942 Protected => 1, 943 ValueConvInv => q{ 944 require Image::ExifTool::XMP; 945 return Image::ExifTool::XMP::FormatXMPDate($val); 946 }, 947 PrintConvInv => '$self->InverseDateTime($val,1,1)', 948 }, 949 0xc71c => { # RawImageDigest 950 Writable => 'int8u', 951 WriteGroup => 'IFD0', 952 Protected => 1, 953 ValueConvInv => 'pack("H*", $val)', 954 }, 955 0xc71d => { # OriginalRawFileDigest 956 Writable => 'int8u', 957 WriteGroup => 'IFD0', 958 Protected => 1, 959 ValueConvInv => 'pack("H*", $val)', 960 }, 961 0xc725 => { # ProfileLookTableDims 962 Writable => 'int32u', 963 Count => 3, 964 WriteGroup => 'IFD0', 965 Protected => 1, 966 }, 967 0xc726 => { # ProfileLookTableData 968 Writable => 'float', 678 969 Count => -1, 679 970 WriteGroup => 'IFD0', … … 692 983 ValueConvInv => q{"Owner's Name: $val"}, 693 984 Notes => q{ 694 tags 0xfde8-0xf e58 are generated by Photoshop Camera RAW -- some695 names are the same as other EXIF tags, but ExifTool will avoid696 writingthese unless they already exist in the file985 tags 0xfde8-0xfdea and 0xfe4c-0xfe58 are generated by Photoshop Camera RAW. 986 Some names are the same as other EXIF tags, but ExifTool will avoid writing 987 these unless they already exist in the file 697 988 }, 698 989 }, … … 791 1082 792 1083 # insert our writable properties into main EXIF tag table 793 InsertWritableProperties( 'Image::ExifTool::Exif::Main', \%writeTable, \&CheckExif);1084 InsertWritableProperties(\%Image::ExifTool::Exif::Main, \%writeTable, \&CheckExif); 794 1085 795 1086 #------------------------------------------------------------------------------ 796 # Change date/time string to standard EXIF formatting797 # Inputs: 0) Date/Timestring798 # Returns: formatted date/time string (or undef and issues warning on error)799 sub ExifDateTime($)1087 # Inverse print conversion for LensInfo 1088 # Inputs: 0) lens info string 1089 # Returns: PrintConvInv of string 1090 sub ConvertLensInfo($) 800 1091 { 801 1092 my $val = shift; 802 my $rtnVal; 803 if ($val =~ /(\d{4})/g) { # get YYYY 804 my $yr = $1; 805 my @a = ($val =~ /\d{2}/g); # get MM, DD, and maybe hh, mm, ss 806 if (@a >= 2) { 807 push @a, '00' while @a < 5; # add hh, mm, ss if not given 808 # construct properly formatted date/time string 809 $rtnVal = "$yr:$a[0]:$a[1] $a[2]:$a[3]:$a[4]"; 810 } 811 } 812 $rtnVal or warn "Improperly formatted date/time\n"; 813 return $rtnVal; 1093 my @a = GetLensInfo($val, 1); # (allow unknown "?" values) 1094 return @a ? join(' ', @a) : $val; 814 1095 } 815 1096 … … 844 1125 #------------------------------------------------------------------------------ 845 1126 # validate raw values for writing 846 # Inputs: 0) ExifTool object reference, 1) tagInfo hash reference, 847 # 2) raw value reference 1127 # Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) raw value ref 848 1128 # Returns: error string or undef (and possibly changes value) on success 849 1129 sub CheckExif($$$) 850 1130 { 851 1131 my ($exifTool, $tagInfo, $valPtr) = @_; 852 my $format = $$tagInfo{Format} || $$tagInfo{Writable} || $tagInfo->{Table} ->{WRITABLE};1132 my $format = $$tagInfo{Format} || $$tagInfo{Writable} || $tagInfo->{Table}{WRITABLE}; 853 1133 if (not $format or $format eq '1') { 854 if ($tagInfo->{Groups} ->{0} eq 'MakerNotes') {1134 if ($tagInfo->{Groups}{0} eq 'MakerNotes') { 855 1135 return undef; # OK to have no format for makernotes 856 1136 } else { … … 865 1145 # Inputs: 0) ExifTool ref, 1) text string 866 1146 # Returns: encoded string 1147 # Note: MUST be called Raw conversion time so the EXIF byte order is known! 867 1148 sub EncodeExifText($$) 868 1149 { … … 870 1151 # does the string contain special characters? 871 1152 if ($val =~ /[\x80-\xff]/) { 872 return "UNICODE\0" . $exifTool->Charset2Unicode($val); 1153 my $order = $exifTool->GetNewValues('ExifUnicodeByteOrder'); 1154 return "UNICODE\0" . $exifTool->Encode($val,'UCS2',$order); 873 1155 } else { 874 1156 return "ASCII\0\0\0$val"; … … 878 1160 #------------------------------------------------------------------------------ 879 1161 # insert writable properties into main tag table 880 # Inputs: 0) tag table name, 1) reference to writable properties1162 # Inputs: 0) tag table ref, 1) reference to writable properties 881 1163 # 2) [optional] CHECK_PROC reference 882 1164 sub InsertWritableProperties($$;$) 883 1165 { 884 my ($ta bleName, $writeTablePtr, $checkProc) = @_;1166 my ($tagTablePtr, $writeTablePtr, $checkProc) = @_; 885 1167 my $tag; 886 my $tagTablePtr = GetTagTable($tableName);887 1168 $checkProc and $tagTablePtr->{CHECK_PROC} = $checkProc; 888 1169 foreach $tag (keys %$writeTablePtr) { … … 895 1176 my $key; 896 1177 foreach $key (%$writeInfo) { 897 $$tagInfo{$key} = $$writeInfo{$key} ;1178 $$tagInfo{$key} = $$writeInfo{$key} unless defined $$tagInfo{$key}; 898 1179 } 899 1180 } else { 900 $$tagInfo{Writable} = $writeInfo ;1181 $$tagInfo{Writable} = $writeInfo unless defined $$tagInfo{Writable}; 901 1182 } 902 1183 } … … 910 1191 # rebuild maker notes to properly contain all value data 911 1192 # (some manufacturers put value data outside maker notes!!) 912 # Inputs: 0) ExifTool object reference, 1) tag table reference, 913 # 2) dirInfo reference 1193 # Inputs: 0) ExifTool object ref, 1) tag table ref, 2) dirInfo ref 914 1194 # Returns: new maker note data (and creates MAKER_NOTE_FIXUP), or undef on error 915 1195 sub RebuildMakerNotes($$$) … … 925 1205 delete $exifTool->{MAKER_NOTE_FIXUP}; 926 1206 927 # don't need to rebuild text or binary-datamaker notes1207 # don't need to rebuild text, BinaryData or PreviewImage maker notes 928 1208 my $tagInfo = $$dirInfo{TagInfo}; 929 1209 my $subdir = $$tagInfo{SubDirectory}; 930 1210 my $proc = $$subdir{ProcessProc} || $$tagTablePtr{PROCESS_PROC} || \&ProcessExif; 931 1211 if (($proc ne \&ProcessExif and $$tagInfo{Name} =~ /Text/) or 932 $proc eq \&Image::ExifTool::ProcessBinaryData) 1212 $proc eq \&Image::ExifTool::ProcessBinaryData or 1213 ($$tagInfo{PossiblePreview} and $dirLen > 6 and 1214 substr($$dataPt, $dirStart, 3) eq "\xff\xd8\xff")) 933 1215 { 934 1216 return substr($$dataPt, $dirStart, $dirLen); … … 940 1222 # create new exiftool object to rewrite the directory without changing it 941 1223 my $newTool = new Image::ExifTool; 1224 $newTool->Init(); # must do this before calling WriteDirectory()! 942 1225 # don't copy over preview image 943 1226 $newTool->SetNewValue(PreviewImage => ''); 944 1227 # copy all transient members over in case they are used for writing 945 # ( CameraMake, CameraModel, etc)1228 # (Make, Model, etc) 946 1229 foreach (grep /[a-z]/, keys %$exifTool) { 947 1230 $$newTool{$_} = $$exifTool{$_}; … … 949 1232 # fix base offsets if specified 950 1233 $newTool->Options(FixBase => $exifTool->Options('FixBase')); 951 # set FILE_TYPE to JPEGso PREVIEW_INFO will be generated952 $newTool->{ FILE_TYPE} = 'JPEG';1234 # set GENERATE_PREVIEW_INFO flag so PREVIEW_INFO will be generated 1235 $newTool->{GENERATE_PREVIEW_INFO} = 1; 953 1236 # drop any large tags 954 1237 $newTool->{DROP_TAGS} = 1; 1238 # initialize other necessary data members 1239 $newTool->{FILE_TYPE} = $exifTool->{FILE_TYPE}; 1240 $newTool->{TIFF_TYPE} = $exifTool->{TIFF_TYPE}; 955 1241 # rewrite maker notes 956 1242 $rtnValue = $newTool->WriteDirectory(\%subdirInfo, $tagTablePtr); 957 1243 if (defined $rtnValue and length $rtnValue) { 958 # add the dummy preview image if necessary1244 # add the dummy/empty preview image if necessary 959 1245 if ($newTool->{PREVIEW_INFO}) { 960 1246 $makerFixup->SetMarkerPointers(\$rtnValue, 'PreviewImage', length($rtnValue)); 961 $rtnValue .= $newTool->{PREVIEW_INFO} ->{Data};1247 $rtnValue .= $newTool->{PREVIEW_INFO}{Data}; 962 1248 delete $newTool->{PREVIEW_INFO}; 963 1249 } 964 1250 # add makernote header 965 $loc and $rtnValue = substr($$dataPt, $dirStart, $loc) . $rtnValue; 966 # adjust fixup for shift in start position 967 $makerFixup->{Start} += $loc; 1251 if ($loc) { 1252 my $hdr = substr($$dataPt, $dirStart, $loc); 1253 # special case: convert Pentax/Samsung DNG maker notes to JPEG style 1254 # (in JPEG, Pentax makernotes are absolute and start with "AOC\0") 1255 if ($hdr =~ s/^(PENTAX |SAMSUNG)\0/AOC\0/) { 1256 # save fixup so we will adjust to absolute offsets when writing 1257 $exifTool->{MAKER_NOTE_FIXUP} = $makerFixup; 1258 } 1259 $rtnValue = $hdr . $rtnValue; 1260 # adjust fixup for shift in start position 1261 $makerFixup->{Start} += length $hdr; 1262 } 968 1263 # shift offsets according to original position of maker notes, 969 1264 # and relative to the makernotes Base … … 974 1269 # fix up pointers to the specified offset 975 1270 $makerFixup->ApplyFixup(\$rtnValue); 976 }977 # save fixup information unless offsets were relative978 unless ($subdirInfo{Relative}) {979 # set shift so offsets are all relative to start of maker notes980 $makerFixup->{Shift} -= $dataPos + $dirStart;981 $exifTool->{MAKER_NOTE_FIXUP} = $makerFixup; # save fixup for later1271 # save fixup information unless offsets were relative 1272 unless ($subdirInfo{Relative}) { 1273 # set shift so offsets are all relative to start of maker notes 1274 $makerFixup->{Shift} -= $dataPos + $dirStart; 1275 $exifTool->{MAKER_NOTE_FIXUP} = $makerFixup; # save fixup for later 1276 } 982 1277 } 983 1278 } … … 995 1290 my ($index, %entries); 996 1291 # split the directory into separate entries 997 my ($padding, $newDir) = ('','');1292 my $newDir = ''; 998 1293 for ($index=0; $index<$numEntries; ++$index) { 999 1294 my $entry = $dirStart + 2 + 12 * $index; … … 1003 1298 $tagID = 0x10000 unless $tagID or $index == 0; 1004 1299 # add new entry (allow for duplicate tag ID's, which shouldn't normally happen) 1005 $entries{$tagID} or $entries{$tagID} = ''; 1006 $entries{$tagID} .= $entryData; 1300 if ($entries{$tagID}) { 1301 $entries{$tagID} .= $entryData; 1302 } else { 1303 $entries{$tagID} = $entryData; 1304 } 1007 1305 } 1008 1306 # sort the directory entries … … 1012 1310 } 1013 1311 # replace original directory with new, sorted one 1014 substr($$dataPt, $dirStart + 2, 12 * $numEntries) = $newDir . $padding;1312 substr($$dataPt, $dirStart + 2, 12 * $numEntries) = $newDir; 1015 1313 } 1016 1314 … … 1036 1334 my $entry = 12 * $index; 1037 1335 my $tagID = Get16u(\$buff, $entry); 1038 $tagID > $lastID or return 0;1336 $tagID > $lastID or $$dirInfo{AllowOutOfOrderTags} or return 0; 1039 1337 my $format = Get16u(\$buff, $entry+2); 1040 1338 $format > 0 and $format <= 13 or return 0; … … 1044 1342 } 1045 1343 return 1; 1344 } 1345 1346 #------------------------------------------------------------------------------ 1347 # Get sorted list of offsets used in IFD 1348 # Inputs: 0) data ref, 1) directory start, 2) dataPos, 3) IFD entries, 4) tag table ref 1349 # Returns: 0) sorted list of offsets (only offsets after the end of the IFD) 1350 # 1) hash of list indices keyed by offset value 1351 # Notes: This is used in a patch to fix the count for tags in Kodak SubIFD3 1352 sub GetOffList($$$$$) 1353 { 1354 my ($dataPt, $dirStart, $dataPos, $numEntries, $tagTablePtr) = @_; 1355 my $ifdEnd = $dirStart + 2 + 12 * $numEntries + $dataPos; 1356 my ($index, $offset, %offHash); 1357 for ($index=0; $index<$numEntries; ++$index) { 1358 my $entry = $dirStart + 2 + 12 * $index; 1359 my $format = Get16u($dataPt, $entry + 2); 1360 next if $format < 1 or $format > 13; 1361 my $count = Get16u($dataPt, $entry + 4); 1362 my $size = $formatSize[$format] * $count; 1363 if ($size <= 4) { 1364 my $tagID = Get16u($dataPt, $entry); 1365 next unless ref $$tagTablePtr{$tagID} eq 'HASH' and $$tagTablePtr{$tagID}{FixCount}; 1366 } 1367 my $offset = Get16u($dataPt, $entry + 8); 1368 $offHash{$offset} = 1 if $offset >= $ifdEnd; 1369 } 1370 # set offset hash values to indices in list 1371 my @offList = sort keys %offHash; 1372 $index = 0; 1373 foreach $offset (@offList) { 1374 $offHash{$offset} = $index++; 1375 } 1376 return(\@offList, \%offHash); 1046 1377 } 1047 1378 … … 1061 1392 #------------------------------------------------------------------------------ 1062 1393 # Handle error while writing EXIF 1063 # Inputs: 0) ExifTool ref, 1) error string, 2) flag set for minor error1394 # Inputs: 0) ExifTool ref, 1) error string, 2) tag table ref 1064 1395 # Returns: undef on fatal error, or '' if minor error is ignored 1065 1396 sub ExifErr($$$) 1066 1397 { 1067 my ($exifTool, $errStr, $minor) = @_; 1398 my ($exifTool, $errStr, $tagTablePtr) = @_; 1399 # MakerNote errors are minor by default 1400 my $minor = ($tagTablePtr->{GROUPS}{0} eq 'MakerNotes'); 1401 if ($tagTablePtr->{VARS} and $tagTablePtr->{VARS}{MINOR_ERRORS}) { 1402 $exifTool->Warn("$errStr. IFD dropped.") and return '' if $minor; 1403 $minor = 1; 1404 } 1068 1405 return undef if $exifTool->Error($errStr, $minor); 1069 1406 return ''; … … 1071 1408 1072 1409 #------------------------------------------------------------------------------ 1410 # Read/Write IFD with TIFF-like header (used by DNG 1.2) 1411 # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref 1412 # Returns: Reading: 1 on success, otherwise returns 0 and sets a Warning 1413 # Writing: new data block or undef on error 1414 sub ProcessTiffIFD($$$) 1415 { 1416 my ($exifTool, $dirInfo, $tagTablePtr) = @_; 1417 $exifTool or return 1; # allow dummy access 1418 my $raf = $$dirInfo{RAF}; 1419 my $base = $$dirInfo{Base} || 0; 1420 my $dirName = $$dirInfo{DirName}; 1421 my $magic = $dirInfo->{Subdir}{Magic} || 0x002a; 1422 my $buff; 1423 1424 # structured with a TIFF-like header and relative offsets 1425 $raf->Seek($base, 0) and $raf->Read($buff, 8) == 8 or return 0; 1426 unless (SetByteOrder(substr($buff,0,2)) and Get16u(\$buff, 2) == $magic) { 1427 my $msg = "Invalid $dirName header"; 1428 if ($$dirInfo{IsWriting}) { 1429 $exifTool->Error($msg); 1430 return undef; 1431 } else { 1432 $exifTool->Warn($msg); 1433 return 0; 1434 } 1435 } 1436 my $offset = Get32u(\$buff, 4); 1437 my %dirInfo = ( 1438 DirName => $$dirInfo{DirName}, 1439 Parent => $$dirInfo{Parent}, 1440 Base => $base, 1441 DataPt => \$buff, 1442 DataLen => length $buff, 1443 DataPos => 0, 1444 DirStart => $offset, 1445 DirLen => length($buff) - $offset, 1446 RAF => $raf, 1447 NewDataPos => 8, 1448 ); 1449 if ($$dirInfo{IsWriting}) { 1450 # rewrite the Camera Profile IFD 1451 my $newDir = WriteExif($exifTool, \%dirInfo, $tagTablePtr); 1452 # don't add header if error writing directory ($newDir is undef) 1453 # or if directory is being deleted ($newDir is empty) 1454 return $newDir unless $newDir; 1455 # return directory with TIFF-like header 1456 return GetByteOrder() . Set16u($magic) . Set32u(8) . $newDir; 1457 } 1458 if ($exifTool->{HTML_DUMP}) { 1459 my $tip = sprintf("Byte order: %s endian\nIdentifier: 0x%.4x\n%s offset: 0x%.4x", 1460 (GetByteOrder() eq 'II') ? 'Little' : 'Big', $magic, $dirName, $offset); 1461 $exifTool->HDump($base, 8, "$dirName header", $tip, 0); 1462 } 1463 return ProcessExif($exifTool, \%dirInfo, $tagTablePtr); 1464 } 1465 1466 #------------------------------------------------------------------------------ 1073 1467 # Write EXIF directory 1074 # Inputs: 0) ExifTool object reference, 1) source dirInfo reference, 1075 # 2) tag table reference 1468 # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref 1076 1469 # Returns: Exif data block (may be empty if no Exif data) or undef on error 1077 1470 # Notes: Increments ExifTool CHANGED flag for each tag changed. Also updates … … 1086 1479 { 1087 1480 my ($exifTool, $dirInfo, $tagTablePtr) = @_; 1088 $exifTool or return 1; # allow dummy access to autoload this package 1481 $exifTool or return 1; # allow dummy access to autoload this package 1482 my $origDirInfo = $dirInfo; # save original dirInfo 1089 1483 my $dataPt = $$dirInfo{DataPt}; 1090 1484 unless ($dataPt) { … … 1101 1495 my $dirName = $$dirInfo{DirName} || 'unknown'; 1102 1496 my $fixup = $$dirInfo{Fixup} || new Image::ExifTool::Fixup; 1497 my $imageDataFlag = $$dirInfo{ImageData} || ''; 1103 1498 my $verbose = $exifTool->Options('Verbose'); 1104 1499 my $out = $exifTool->Options('TextOut'); 1500 my ($nextIfdPos, %offsetData, $inMakerNotes); 1105 1501 my (@offsetInfo, %xDelete); 1502 my $deleteAll = 0; 1106 1503 my $newData = ''; # initialize buffer to receive new directory data 1107 my ($nextIfdPos, %offsetData, $inMakerNotes); 1108 my $deleteAll = 0; 1504 my @imageData; # image data blocks to copy later if requested 1505 my $name = $$dirInfo{Name}; 1506 $name = $dirName unless $name and $dirName eq 'MakerNotes' and $name !~ /^MakerNote/; 1109 1507 1110 1508 # allow multiple IFD's in IFD0-IFD1-IFD2... chain 1111 $$dirInfo{Multi} = 1 if $dirName eq 'IFD0' or $dirName eq 'SubIFD';1112 $inMakerNotes = 1 if $tagTablePtr->{GROUPS} ->{0} eq 'MakerNotes';1509 $$dirInfo{Multi} = 1 if $dirName =~ /^(IFD0|SubIFD)$/ and not defined $$dirInfo{Multi}; 1510 $inMakerNotes = 1 if $tagTablePtr->{GROUPS}{0} eq 'MakerNotes'; 1113 1511 my $ifd; 1114 1512 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ … … 1117 1515 for ($ifd=0; ; ++$ifd) { # loop through multiple IFD's 1118 1516 1517 # save pointer to start of this IFD within the newData 1518 my $newStart = length($newData); 1519 my @subdirs; # list of subdirectory data and tag table pointers 1520 # determine if directory is contained within our data 1521 my $mustRead; 1522 if ($dirStart < 0 or $dirStart > $dataLen-2) { 1523 $mustRead = 1; 1524 } elsif ($dirLen > 2) { 1525 my $len = 2 + 12 * Get16u($dataPt, $dirStart); 1526 $mustRead = 1 if $dirStart + $len > $dataLen; 1527 } 1528 # read IFD from file if necessary 1529 if ($mustRead) { 1530 if ($raf) { 1531 # read the count of entries in this IFD 1532 my $offset = $dirStart + $dataPos; 1533 my ($buff, $buf2); 1534 unless ($raf->Seek($offset + $base, 0) and $raf->Read($buff,2) == 2) { 1535 return ExifErr($exifTool, "Bad IFD or truncated file in $name", $tagTablePtr); 1536 } 1537 my $len = 12 * Get16u(\$buff,0); 1538 # (also read next IFD pointer if available) 1539 unless ($raf->Read($buf2, $len+4) >= $len) { 1540 return ExifErr($exifTool, "Error reading $name", $tagTablePtr); 1541 } 1542 $buff .= $buf2; 1543 # make copy of dirInfo since we're going to modify it 1544 my %newDirInfo = %$dirInfo; 1545 $dirInfo = \%newDirInfo; 1546 # update directory parameters for the newly loaded IFD 1547 $dataPt = $$dirInfo{DataPt} = \$buff; 1548 $dirStart = $$dirInfo{DirStart} = 0; 1549 $dataPos = $$dirInfo{DataPos} = $offset; 1550 $dataLen = $$dirInfo{DataLen} = length $buff; 1551 $dirLen = $$dirInfo{DirLen} = $dataLen; 1552 # only account for nextIFD pointer if we are going to use it 1553 $len += 4 if $dataLen==$len+6 and ($$dirInfo{Multi} or $buff =~ /\0{4}$/); 1554 UpdateTiffEnd($exifTool, $offset+$base+2+$len); 1555 } elsif ($dirLen) { 1556 # error if we can't load IFD (unless we are creating 1557 # from scratch, in which case dirLen will be zero) 1558 my $str = $exifTool->Options('IgnoreMinorErrors') ? 'Deleted bad' : 'Bad'; 1559 $exifTool->Error("$str $name directory", 1); 1560 } 1561 } 1562 my ($index, $dirEnd, $numEntries); 1563 if ($dirStart + 4 < $dataLen) { 1564 $numEntries = Get16u($dataPt, $dirStart); 1565 $dirEnd = $dirStart + 2 + 12 * $numEntries; 1566 if ($dirEnd > $dataLen) { 1567 return ExifErr($exifTool, "Truncated $name directory", $tagTablePtr); 1568 } 1569 # sort entries if necessary (but not in maker notes IFDs) 1570 unless ($inMakerNotes) { 1571 my $lastID = -1; 1572 for ($index=0; $index<$numEntries; ++$index) { 1573 my $tagID = Get16u($dataPt, $dirStart + 2 + 12 * $index); 1574 # check for proper sequence (but ignore null entries at end) 1575 if ($tagID < $lastID and $tagID) { 1576 SortIFD($dataPt, $dirStart, $numEntries); 1577 $exifTool->Warn("Entries in $name were out of sequence. Fixed.",1); 1578 last; 1579 } 1580 $lastID = $tagID; 1581 } 1582 } 1583 } else { 1584 $numEntries = 0; 1585 $dirEnd = $dirStart; 1586 } 1587 1119 1588 # loop through new values and accumulate all information for this IFD 1120 1589 my (%set, $tagInfo); 1121 my $tableGroup = $tagTablePtr->{GROUPS}->{0};1122 1590 my $wrongDir = $crossDelete{$dirName}; 1123 1591 foreach $tagInfo ($exifTool->GetNewTagInfoList($tagTablePtr)) { … … 1134 1602 } 1135 1603 if (defined $val) { 1136 $curInfo = $exifTool->GetTagInfo($tagTablePtr, $tagID, \$val, 1137 $$tagInfo{Format} || 'undef', $$tagInfo{Count} || 1); 1604 my $fmt = $$tagInfo{Writable} || $$tagInfo{Format} || 'undef'; 1605 my $cnt = $$tagInfo{Count} || 1; 1606 # always use old format/count for Condition in maker notes 1607 if ($inMakerNotes) { 1608 for ($index=0; $index<$numEntries; ++$index) { 1609 my $entry = $dirStart + 2 + 12 * $index; 1610 my $id = Get16u($dataPt, $entry); 1611 if ($id eq $tagID) { 1612 my $f = Get16u($dataPt, $entry + 2); 1613 if ($formatName[$f]) { 1614 $fmt = $formatName[$f]; 1615 $cnt = Get32u($dataPt, $entry + 4); 1616 } 1617 last; 1618 } 1619 } 1620 } 1621 $curInfo = $exifTool->GetTagInfo($tagTablePtr, $tagID, \$val, $fmt, $cnt); 1138 1622 } 1139 1623 } … … 1149 1633 } 1150 1634 } 1151 my $n ewValueHash = $exifTool->GetNewValueHash($tagInfo, $dirName);1152 unless ($n ewValueHash) {1635 my $nvHash = $exifTool->GetNewValueHash($tagInfo, $dirName); 1636 unless ($nvHash) { 1153 1637 next unless $wrongDir; 1154 1638 # delete stuff from the wrong directory if setting somewhere else 1155 $n ewValueHash = $exifTool->GetNewValueHash($tagInfo, $wrongDir);1156 next unless Image::ExifTool::IsOverwriting($n ewValueHash);1639 $nvHash = $exifTool->GetNewValueHash($tagInfo, $wrongDir); 1640 next unless Image::ExifTool::IsOverwriting($nvHash); 1157 1641 # don't cross delete if specifically deleting from the other directory 1158 my $val = Image::ExifTool::GetNewValues($n ewValueHash);1159 next if not defined $val and $n ewValueHash->{WantGroup} and1160 lc($n ewValueHash->{WantGroup}) eq lc($wrongDir);1642 my $val = Image::ExifTool::GetNewValues($nvHash); 1643 next if not defined $val and $nvHash->{WantGroup} and 1644 lc($nvHash->{WantGroup}) eq lc($wrongDir); 1161 1645 # remove this tag if found in this IFD 1162 1646 $xDelete{$tagID} = 1; 1163 1647 } 1164 $set{$tagID} = $tagInfo; 1165 } 1166 # save pointer to start of this IFD within the newData 1167 my $newStart = length($newData); 1168 my @subdirs; # list of subdirectory data and tag table pointers 1169 # determine if directory is contained within our data 1170 my $mustRead; 1171 if ($dirStart < 0 or $dirStart > $dataLen-2) { 1172 $mustRead = 1; 1173 } elsif ($dirLen > 2) { 1174 my $len = 2 + 12 * Get16u($dataPt, $dirStart); 1175 $mustRead = 1 if $dirStart + $len > $dataLen; 1176 } 1177 # read IFD from file if necessary 1178 if ($raf and $mustRead) { 1179 # read the count of entries in this IFD 1180 my $offset = $dirStart + $dataPos; 1181 my ($buff, $buf2); 1182 unless ($raf->Seek($offset + $base, 0) and $raf->Read($buff,2) == 2) { 1183 return ExifErr($exifTool, "Bad IFD or truncated file in $dirName", $inMakerNotes); 1184 } 1185 my $len = 12 * Get16u(\$buff,0); 1186 # (also read next IFD pointer if available) 1187 unless ($raf->Read($buf2, $len+4) >= $len) { 1188 return ExifErr($exifTool, "Error reading $dirName", $inMakerNotes); 1189 } 1190 $buff .= $buf2; 1191 # make copy of dirInfo since we're going to modify it 1192 my %newDirInfo = %$dirInfo; 1193 $dirInfo = \%newDirInfo; 1194 # update directory parameters for the newly loaded IFD 1195 $dataPt = $$dirInfo{DataPt} = \$buff; 1196 $dirStart = $$dirInfo{DirStart} = 0; 1197 $dataPos = $$dirInfo{DataPos} = $offset; 1198 $dataLen = $$dirInfo{DataLen} = length $buff; 1199 $dirLen = $$dirInfo{DirLen} = $dataLen; 1200 # only account for nextIFD pointer if we are going to use it 1201 $len += 4 if $dataLen==$len+6 and ($$dirInfo{Multi} or $buff =~ /\0{4}$/); 1202 UpdateTiffEnd($exifTool, $offset+$base+2+$len); 1203 } 1204 my ($len, $numEntries); 1205 if ($dirStart + 4 < $dataLen) { 1206 $numEntries = Get16u($dataPt, $dirStart); 1207 $len = 2 + 12 * $numEntries; 1208 if ($dirStart + $len > $dataLen) { 1209 return ExifErr($exifTool, "Truncated $dirName directory", $inMakerNotes); 1210 } 1211 # sort entries if necessary (but not in maker notes IFDs) 1212 unless ($inMakerNotes) { 1213 my $index; 1214 my $lastID = -1; 1215 for ($index=0; $index<$numEntries; ++$index) { 1216 my $tagID = Get16u($dataPt, $dirStart + 2 + 12 * $index); 1217 # check for proper sequence (but ignore null entries at end) 1218 if ($tagID < $lastID and $tagID) { 1219 SortIFD($dataPt, $dirStart, $numEntries); 1220 $exifTool->Warn("Entries in $dirName were out of sequence. Fixed."); 1221 last; 1222 } 1223 $lastID = $tagID; 1648 if ($set{$tagID}) { 1649 # this tag is being set twice, which can happen if two Condition's 1650 # were true for this tag. Hopefully the only case where this can 1651 # happen is the MakerNotes tag since it may store two very different 1652 # types of information (MakerNotes and PreviewImage), but we want 1653 # to store the MakerNotes if both are available 1654 if ($tagID == 0x927c and $dirName =~ /^(ExifIFD|IFD0)$/) { 1655 next if $$tagInfo{Name} eq 'PreviewImage'; 1656 } else { 1657 $exifTool->Warn(sprintf("Multiple new values for $name tag 0x%.4x",$tagID)); 1224 1658 } 1225 1659 } 1226 } else {1227 $numEntries = $len = 0;1228 }1229 1230 # fix base offsets1231 if ($dirName eq 'MakerNotes' and $$dirInfo{Parent} eq 'ExifIFD'and1660 $set{$tagID} = $tagInfo; 1661 } 1662 1663 # fix base offsets (some cameras incorrectly write maker notes in IFD0) 1664 if ($dirName eq 'MakerNotes' and $$dirInfo{Parent} =~ /^(ExifIFD|IFD0)$/ and 1665 $$exifTool{TIFF_TYPE} !~ /^(ARW|SR2)$/ and not $$exifTool{LeicaTrailerPos} and 1232 1666 Image::ExifTool::MakerNotes::FixBase($exifTool, $dirInfo)) 1233 1667 { … … 1239 1673 # initialize variables to handle mandatory tags 1240 1674 my $mandatory = $mandatory{$dirName}; 1241 my $allMandatory;1675 my ($allMandatory, $addMandatory); 1242 1676 if ($mandatory) { 1243 1677 # use X/Y resolution values from JFIF if available … … 1249 1683 $mandatory = \%ifd0Vals; 1250 1684 } 1251 $allMandatory = 0;# initialize to zero1685 $allMandatory = $addMandatory = 0; # initialize to zero 1252 1686 # add mandatory tags if creating a new directory 1253 1687 unless ($numEntries) { … … 1261 1695 my ($addDirs, @newTags); 1262 1696 if ($inMakerNotes) { 1263 $addDirs = { }; 1697 $addDirs = { }; # can't currently add new directories in MakerNotes 1698 # allow non-permanent makernotes tags to be added 1699 # (note: we may get into trouble if there are too many of these 1700 # because we allow out-of-order tags in MakerNote IFD's but our 1701 # logic to add new tags relies on ordered entries) 1702 foreach (keys %set) { 1703 my $perm = $set{$_}{Permanent}; 1704 push @newTags, $_ if defined $perm and not $perm; 1705 } 1706 @newTags = sort { $a <=> $b } @newTags if @newTags > 1; 1264 1707 } else { 1265 1708 # get a hash of directories we will be writing in this one … … 1279 1722 my $dirFixup = new Image::ExifTool::Fixup; 1280 1723 my $entryBasedFixup; 1281 my $index = 0;1282 1724 my $lastTagID = -1; 1283 my ($oldInfo, $oldFormat, $oldFormName, $oldCount, $oldSize, $oldValue );1725 my ($oldInfo, $oldFormat, $oldFormName, $oldCount, $oldSize, $oldValue, $oldImageData); 1284 1726 my ($readFormat, $readFormName, $readCount); # format for reading old value(s) 1285 1727 my ($entry, $valueDataPt, $valueDataPos, $valueDataLen, $valuePtr, $valEnd); 1728 my ($offList, $offHash, $ignoreCount, $fixCount); 1286 1729 my $oldID = -1; 1287 1730 my $newID = -1; 1731 1732 # patch for Canon EOS 40D firmware 1.0.4 bug (incorrect directory counts) 1733 if ($inMakerNotes and $$exifTool{Model} eq 'Canon EOS 40D') { 1734 my $fmt = Get16u($dataPt, $dirStart + 2 + 12 * ($numEntries - 1) + 2); 1735 if ($fmt < 1 or $fmt > 13) { 1736 # adjust the number of directory entries 1737 --$numEntries; 1738 $dirEnd -= 12; 1739 $ignoreCount = 1; 1740 } 1741 } 1288 1742 #.............................................................................. 1289 1743 # loop through entries in new directory 1290 1744 # 1745 $index = 0; 1291 1746 Entry: for (;;) { 1292 1747 … … 1300 1755 $readFormat = $oldFormat = Get16u($dataPt, $entry+2); 1301 1756 $readCount = $oldCount = Get32u($dataPt, $entry+4); 1757 undef $oldImageData; 1302 1758 if ($oldFormat < 1 or $oldFormat > 13) { 1759 # patch to preserve invalid directory entries in SubIFD3 of 1760 # various Kodak Z-series cameras (Z812, Z1085IS, Z1275) 1761 if ($dirName eq 'MakerNotes' and $$exifTool{Make}=~/KODAK/i and 1762 $$dirInfo{Name} and $$dirInfo{Name} eq 'SubIFD3') 1763 { 1764 $dirBuff .= substr($$dataPt, $entry, 12); 1765 goto WroteIt; 1766 } 1303 1767 # don't write out null directory entry 1304 unless ($oldFormat or $oldCount or not $index) { 1305 ++$index; 1306 $newID = $oldID; # pretend we wrote this 1768 if ($oldFormat==0 and $index and $oldCount==0) { 1769 $ignoreCount = ($ignoreCount || 0) + 1; 1307 1770 # must keep same directory size to avoid messing up our fixed offsets 1308 1771 $dirBuff .= ("\0" x 12) if $$dirInfo{FixBase}; 1772 WroteIt: ++$index; 1773 $newID = $oldID; # pretend we wrote this 1309 1774 next; 1310 1775 } 1311 return ExifErr($exifTool, "Bad format ($oldFormat) for $dirName entry $index", $inMakerNotes); 1776 my $msg = "Bad format ($oldFormat) for $name entry $index"; 1777 return ExifErr($exifTool, $msg, $tagTablePtr); 1312 1778 } 1313 1779 $readFormName = $oldFormName = $formatName[$oldFormat]; … … 1316 1782 $valueDataLen = $dataLen; 1317 1783 $valuePtr = $entry + 8; 1318 $oldSize = $oldCount * $formatSize[$oldFormat]; 1319 # must try direct method first so we will get unknown tags too 1320 # (this is necessary so we don't miss a tag we want to Drop) 1784 # try direct method first for speed 1321 1785 $oldInfo = $$tagTablePtr{$oldID}; 1322 1786 if (ref $oldInfo ne 'HASH' or $$oldInfo{Condition}) { 1787 # must get unknown tags too 1788 # (necessary so we don't miss a tag we want to Drop) 1789 my $unk = $exifTool->Options(Unknown => 1); 1323 1790 $oldInfo = $exifTool->GetTagInfo($tagTablePtr, $oldID); 1324 } 1791 $exifTool->Options(Unknown => $unk); 1792 } 1793 # patch incorrect count in Kodak SubIFD3 tags 1794 if ($oldCount < 2 and $oldInfo and $$oldInfo{FixCount}) { 1795 $offList or ($offList, $offHash) = GetOffList($dataPt, $dirStart, $dataPos, 1796 $numEntries, $tagTablePtr); 1797 my $i = $$offHash{Get32u($dataPt, $valuePtr)}; 1798 if (defined $i and $i < $#$offList) { 1799 $oldCount = int(($$offList[$i+1] - $$offList[$i]) / $formatSize[$oldFormat]); 1800 $fixCount = ($fixCount || 0) + 1 if $oldCount != $readCount; 1801 } 1802 } 1803 $oldSize = $oldCount * $formatSize[$oldFormat]; 1325 1804 my $readFromFile; 1326 1805 if ($oldSize > 4) { … … 1330 1809 $valEnd or $valEnd = $dataPos + $dirStart + 2 + 12 * $numEntries + 4; 1331 1810 my ($tagID, $size, $wFlag) = ($oldID, $oldSize, 1); 1332 #### eval FixOffsets ($valuePtr, $valEnd, $size, $tagID, $wFlag)1811 #### eval FixOffsets ($valuePtr, $valEnd, $size, $tagID, $wFlag) 1333 1812 eval $$dirInfo{FixOffsets}; 1334 1813 unless (defined $valuePtr) { 1335 1814 unless ($$exifTool{DROP_TAGS}) { 1336 1815 my $tagStr = $oldInfo ? $$oldInfo{Name} : sprintf("tag 0x%x",$oldID); 1337 return undef if $exifTool->Error("Bad $ dirName directory pointerfor $tagStr", $inMakerNotes);1816 return undef if $exifTool->Error("Bad $name offset for $tagStr", $inMakerNotes); 1338 1817 } 1339 1818 goto DropTag; 1340 1819 } 1341 1820 } 1821 # offset shouldn't point into TIFF or IFD header 1822 my $suspect = ($valuePtr < 8); 1342 1823 # convert offset to pointer in $$dataPt 1343 1824 if ($$dirInfo{EntryBased} or (ref $$tagTablePtr{$oldID} eq 'HASH' and 1344 $tagTablePtr->{$oldID} ->{EntryBased}))1825 $tagTablePtr->{$oldID}{EntryBased})) 1345 1826 { 1346 1827 $valuePtr += $entry; … … 1348 1829 $valuePtr -= $dataPos; 1349 1830 } 1831 # value shouldn't overlap our directory 1832 $suspect = 1 if $valuePtr < $dirEnd and $valuePtr+$oldSize > $dirStart; 1350 1833 # get value by seeking in file if we are allowed 1351 1834 if ($valuePtr < 0 or $valuePtr+$oldSize > $dataLen) { 1352 my ($pos, $tagStr, $invalidPreview );1835 my ($pos, $tagStr, $invalidPreview, $tmpInfo); 1353 1836 if ($oldInfo) { 1354 1837 $tagStr = $$oldInfo{Name}; 1355 1838 } elsif (defined $oldInfo) { 1356 my$tmpInfo = $exifTool->GetTagInfo($tagTablePtr, $oldID, \ '', $oldFormName, $oldCount);1839 $tmpInfo = $exifTool->GetTagInfo($tagTablePtr, $oldID, \ '', $oldFormName, $oldCount); 1357 1840 $tagStr = $$tmpInfo{Name} if $tmpInfo; 1358 1841 } 1359 1842 $tagStr or $tagStr = sprintf("tag 0x%x",$oldID); 1360 # allow PreviewImage to run outside EXIF segment 1361 if (not $raf and $tagStr eq 'PreviewImage') { 1362 $raf = $exifTool->{RAF}; 1363 if ($raf) { 1364 $pos = $raf->Tell(); 1365 } else { 1366 $invalidPreview = 1; 1843 # allow PreviewImage to run outside EXIF segment in JPEG images 1844 if (not $raf) { 1845 if ($tagStr eq 'PreviewImage') { 1846 $raf = $exifTool->{RAF}; 1847 if ($raf) { 1848 $pos = $raf->Tell(); 1849 if ($oldInfo and $$oldInfo{ChangeBase}) { 1850 # adjust base offset for this tag only 1851 #### eval ChangeBase ($dirStart,$dataPos) 1852 my $newBase = eval $$oldInfo{ChangeBase}; 1853 $valuePtr += $newBase; 1854 } 1855 } else { 1856 $invalidPreview = 1; 1857 } 1858 } elsif ($tagStr eq 'MakerNoteLeica6') { 1859 # save information about Leica makernote trailer 1860 $$exifTool{LeicaTrailer} = { 1861 TagInfo => $oldInfo || $tmpInfo, 1862 Offset => $base + $valuePtr + $dataPos, 1863 Size => $oldSize, 1864 }, 1865 $invalidPreview = 2; 1866 # remove SubDirectory to prevent processing (for now) 1867 my %copy = %{$oldInfo || $tmpInfo}; 1868 delete $copy{SubDirectory}; 1869 delete $copy{MakerNotes}; 1870 $oldInfo = \%copy; 1367 1871 } 1368 1872 } 1369 if ($raf) { 1370 my $success = ($raf->Seek($base + $valuePtr + $dataPos, 0) and 1873 if ($oldSize > BINARY_DATA_LIMIT and $$origDirInfo{ImageData} and 1874 (not defined $oldInfo or ($oldInfo and not $$oldInfo{SubDirectory}))) 1875 { 1876 # copy huge data blocks later instead of loading into memory 1877 $oldValue = ''; # dummy empty value 1878 # copy this value later unless writing a new value 1879 unless ($set{$oldID}) { 1880 my $pad = $oldSize & 0x01 ? 1 : 0; 1881 # save block information to copy later (set directory offset later) 1882 $oldImageData = [$base+$valuePtr+$dataPos, $oldSize, $pad]; 1883 } 1884 } elsif ($raf) { 1885 my $success = ($raf->Seek($base+$valuePtr+$dataPos, 0) and 1371 1886 $raf->Read($oldValue, $oldSize) == $oldSize); 1372 1887 if (defined $pos) { 1373 1888 $raf->Seek($pos, 0); 1374 1889 undef $raf; 1375 unless ($success and $oldValue =~ /^(\xff\xd8\xff|.\xd8\xff\xdb)/s) {1376 $exifTool->Error("Bad PreviewImage pointer in $dirName", 1);1890 # (sony A700 has 32-byte header on PreviewImage) 1891 unless ($success and $oldValue =~ /^(\xff\xd8\xff|(.|.{33})\xd8\xff\xdb)/s) { 1377 1892 $invalidPreview = 1; 1378 $success = 1; # continue writing directory 1893 $success = 1; # continue writing directory anyway 1379 1894 } 1380 1895 } 1381 1896 unless ($success) { 1382 return undef if $exifTool->Error("Error reading value for $ dirName entry $index", $inMakerNotes);1897 return undef if $exifTool->Error("Error reading value for $name entry $index", $inMakerNotes); 1383 1898 goto DropTag; 1384 1899 } 1385 1900 } elsif (not $invalidPreview) { 1386 return undef if $exifTool->Error("Bad $ dirName directory pointerfor $tagStr", $inMakerNotes);1901 return undef if $exifTool->Error("Bad $name offset for $tagStr", $inMakerNotes); 1387 1902 goto DropTag; 1388 1903 } 1389 1904 if ($invalidPreview) { 1390 $oldValue = 'none'; # flag for missing preview 1391 $oldSize = length $oldValue; 1905 # set value for invalid preview 1906 if ($exifTool->{FILE_TYPE} eq 'JPEG') { 1907 # define dummy value for preview (or Leica MakerNote) to write later 1908 # (value must be larger than 4 bytes to generate PREVIEW_INFO, 1909 # and an even number of bytes so it won't be padded) 1910 $oldValue = 'LOAD_PREVIEW'; 1911 } else { 1912 $oldValue = 'none'; 1913 $oldSize = length $oldValue; 1914 } 1392 1915 $valuePtr = 0; 1393 1916 } else { … … 1401 1924 $readFromFile = 1; 1402 1925 } 1926 if ($suspect) { 1927 my $tagStr = $oldInfo ? $$oldInfo{Name} : sprintf('tag 0x%.4x', $oldID); 1928 my $str = "Suspicious $name offset for $tagStr"; 1929 if ($inMakerNotes) { 1930 $exifTool->Warn($str, 1); 1931 } else { 1932 return undef if $exifTool->Error($str, 1); 1933 } 1934 } 1403 1935 } 1404 1936 # read value if we haven't already … … 1406 1938 # get tagInfo using value if necessary 1407 1939 if (defined $oldInfo and not $oldInfo) { 1940 my $unk = $exifTool->Options(Unknown => 1); 1408 1941 $oldInfo = $exifTool->GetTagInfo($tagTablePtr, $oldID, \$oldValue, $oldFormName, $oldCount); 1942 $exifTool->Options(Unknown => $unk); 1943 } 1944 # make sure we are handling the 'ifd' format properly 1945 if (($oldFormat == 13 or $oldFormat == 18) and 1946 (not $oldInfo or not $$oldInfo{SubIFD})) 1947 { 1948 my $str = sprintf('%s tag 0x%.4x IFD format not handled', $name, $oldID); 1949 $exifTool->Error($str, $inMakerNotes); 1409 1950 } 1410 1951 # override format we use to read the value if specified 1411 1952 if ($oldInfo) { 1953 # check for tags which must be integers 1954 if (($$oldInfo{IsOffset} or $$oldInfo{SubIFD}) and 1955 not $intFormat{$oldFormName}) 1956 { 1957 $exifTool->Error("Invalid format ($oldFormName) for $name $$oldInfo{Name}", $inMakerNotes); 1958 goto DropTag; 1959 } 1412 1960 if ($$oldInfo{Drop} and $$exifTool{DROP_TAGS}) { 1413 1961 # don't rewrite this tag … … 1431 1979 my $str = $oldInfo ? "$$oldInfo{Name} tag" : sprintf('tag 0x%x',$oldID); 1432 1980 if ($oldID == $lastTagID) { 1433 $exifTool->Warn("Duplicate $str in $ dirName");;1981 $exifTool->Warn("Duplicate $str in $name");; 1434 1982 } else { 1435 $exifTool->Warn("\u$str out of sequence in $ dirName");1983 $exifTool->Warn("\u$str out of sequence in $name"); 1436 1984 } 1437 1985 } … … 1479 2027 $newInfo = $set{$newID}; 1480 2028 $newCount = $$newInfo{Count}; 1481 my ($val, $newVal );1482 my $n ewValueHash = $exifTool->GetNewValueHash($newInfo, $dirName);2029 my ($val, $newVal, $n); 2030 my $nvHash = $exifTool->GetNewValueHash($newInfo, $dirName); 1483 2031 if ($isNew > 0) { 1484 2032 # don't create new entry unless requested 1485 if ($newValueHash) { 1486 next unless Image::ExifTool::IsCreating($newValueHash); 1487 $isOverwriting = Image::ExifTool::IsOverwriting($newValueHash); 2033 if ($nvHash) { 2034 next unless Image::ExifTool::IsCreating($nvHash); 2035 if ($$newInfo{IsOverwriting}) { 2036 my $proc = $$newInfo{IsOverwriting}; 2037 $isOverwriting = &$proc($exifTool, $nvHash, $val, \$newVal); 2038 } else { 2039 $isOverwriting = Image::ExifTool::IsOverwriting($nvHash); 2040 } 1488 2041 } else { 1489 2042 next if $xDelete{$newID}; # don't create if cross deleting … … 1499 2052 $newFormName = $$newInfo{Writable}; 1500 2053 unless ($newFormName) { 1501 warn("No format for $ dirName $$newInfo{Name}\n");2054 warn("No format for $name $$newInfo{Name}\n"); 1502 2055 next; 1503 2056 } 1504 2057 } 1505 2058 $newFormat = $formatNumber{$newFormName}; 1506 } elsif ($n ewValueHash or $xDelete{$newID}) {1507 unless ($n ewValueHash) {1508 $n ewValueHash = $exifTool->GetNewValueHash($newInfo, $wrongDir);2059 } elsif ($nvHash or $xDelete{$newID}) { 2060 unless ($nvHash) { 2061 $nvHash = $exifTool->GetNewValueHash($newInfo, $wrongDir); 1509 2062 } 1510 2063 # read value 1511 2064 $val = ReadValue(\$oldValue, 0, $readFormName, $readCount, $oldSize); 1512 if ($$newInfo{Format}) { 1513 $newFormName = $$newInfo{Format}; 1514 # override existing format if necessary 1515 $ifdFormName = $$newInfo{Writable}; 1516 $ifdFormName = $oldFormName unless $ifdFormName and $ifdFormName ne '1'; 2065 # determine write format (by default, use 'Writable' format) 2066 my $writable = $$newInfo{Writable}; 2067 # (or use existing format if 'Writable' not specified) 2068 $writable = $oldFormName unless $writable and $writable ne '1'; 2069 # (and override write format with 'Format' if specified) 2070 my $writeForm = $$newInfo{Format} || $writable; 2071 if ($writeForm ne $newFormName) { 2072 # write in specified format 2073 $newFormName = $writeForm; 1517 2074 $newFormat = $formatNumber{$newFormName}; 2075 # use different IFD format code if necessary 2076 if ($inMakerNotes) { 2077 # always preserve IFD format in maker notes 2078 $ifdFormName = $oldFormName; 2079 } elsif ($writable ne $newFormName) { 2080 # use specified IFD format 2081 $ifdFormName = $writable; 2082 } 1518 2083 } 1519 2084 if ($inMakerNotes and $readFormName ne 'string' and $readFormName ne 'undef') { … … 1521 2086 $newCount = $oldCount * $formatSize[$oldFormat] / $formatSize[$newFormat]; 1522 2087 } 1523 $isOverwriting = Image::ExifTool::IsOverwriting($newValueHash, $val); 2088 if ($$newInfo{IsOverwriting}) { 2089 my $proc = $$newInfo{IsOverwriting}; 2090 $isOverwriting = &$proc($exifTool, $nvHash, $val, \$newVal); 2091 } else { 2092 $isOverwriting = Image::ExifTool::IsOverwriting($nvHash, $val); 2093 } 1524 2094 } 1525 2095 if ($isOverwriting) { 1526 $newVal = Image::ExifTool::GetNewValues($n ewValueHash) unless defined $newVal;2096 $newVal = Image::ExifTool::GetNewValues($nvHash) unless defined $newVal; 1527 2097 # value undefined if deleting this tag 1528 2098 # (also delete tag if cross-deleting and this isn't a date/time shift) 1529 if (not defined $newVal or ($xDelete{$newID} and not defined $$n ewValueHash{Shift})) {1530 if ($$newInfo{RawConvInv} and defined $$n ewValueHash{Value}) {2099 if (not defined $newVal or ($xDelete{$newID} and not defined $$nvHash{Shift})) { 2100 if ($$newInfo{RawConvInv} and defined $$nvHash{Value}) { 1531 2101 goto NoOverwrite; # error in RawConvInv, so rewrite existing tag 1532 2102 } 1533 2103 unless ($isNew) { 1534 2104 ++$exifTool->{CHANGED}; 1535 $val = $exifTool->Printable($val); 1536 $verbose > 1 and print $out " - $dirName:$$newInfo{Name} = '$val'\n"; 2105 $exifTool->VerboseValue("- $dirName:$$newInfo{Name}", $val); 1537 2106 } 1538 2107 next; 1539 2108 } 1540 if (length $newVal) { 1541 if ($newCount and $newCount < 0) { 1542 # set count to number of values if variable 1543 my @vals = split ' ',$newVal; 1544 $newCount = @vals; 1545 } 1546 # convert to binary format 1547 $newValue = WriteValue($newVal, $newFormName, $newCount); 1548 unless (defined $newValue) { 1549 $exifTool->Warn("Error writing $dirName:$$newInfo{Name}"); 2109 if ($newCount and $newCount < 0) { 2110 # set count to number of values if variable 2111 my @vals = split ' ',$newVal; 2112 $newCount = @vals; 2113 } 2114 # convert to binary format 2115 $newValue = WriteValue($newVal, $newFormName, $newCount); 2116 unless (defined $newValue) { 2117 $exifTool->Warn("Error writing $dirName:$$newInfo{Name}"); 2118 goto NoOverwrite; 2119 } 2120 if (length $newValue) { 2121 # limit maximum value length in JPEG images 2122 # (max segment size is 65533 bytes and the min EXIF size is 96 incl an additional IFD entry) 2123 if ($$exifTool{FILE_TYPE} eq 'JPEG' and length($newValue) > 65436 and 2124 $$newInfo{Name} ne 'PreviewImage') 2125 { 2126 my $name = $$newInfo{MakerNotes} ? 'MakerNotes' : $$newInfo{Name}; 2127 $exifTool->Warn("$name too large to write in JPEG segment"); 1550 2128 goto NoOverwrite; 1551 2129 } 1552 2130 } else { 1553 $exifTool->Warn("Can't write zero length $$newInfo{Name} in $tagTablePtr->{GROUPS} ->{1}");2131 $exifTool->Warn("Can't write zero length $$newInfo{Name} in $tagTablePtr->{GROUPS}{1}"); 1554 2132 goto NoOverwrite; 1555 2133 } … … 1557 2135 $newCount = length($newValue) / $formatSize[$newFormat]; 1558 2136 ++$exifTool->{CHANGED}; 2137 if (defined $allMandatory) { 2138 # not all mandatory if we are writing any tag specifically 2139 if ($nvHash) { 2140 undef $allMandatory; 2141 undef $deleteAll; 2142 } else { 2143 ++$addMandatory; # count mandatory tags that we added 2144 } 2145 } 1559 2146 if ($verbose > 1) { 1560 $val = $exifTool->Printable($val); 1561 $newVal = $exifTool->Printable($newVal); 1562 print $out " - $dirName:$$newInfo{Name} = '$val'\n" unless $isNew; 1563 my $str = $newValueHash ? '' : ' (mandatory)'; 1564 print $out " + $dirName:$$newInfo{Name} = '$newVal'$str\n"; 2147 $exifTool->VerboseValue("- $dirName:$$newInfo{Name}", $val) unless $isNew; 2148 my $str = $nvHash ? '' : ' (mandatory)'; 2149 $exifTool->VerboseValue("+ $dirName:$$newInfo{Name}", $newVal, $str); 1565 2150 } 1566 2151 } … … 1579 2164 # create new subdirectory 1580 2165 # 1581 $newInfo = $$addDirs{$newID} or warn('internal error'), next; 2166 # newInfo may not be defined if we try to add a mandatory tag 2167 # to a directory that doesn't support it (ie. IFD1 in RW2 images) 2168 $newInfo = $$addDirs{$newID} or next; 1582 2169 # make sure we don't try to generate a new MakerNotes directory 1583 2170 # or a SubIFD 1584 2171 next if $$newInfo{MakerNotes} or $$newInfo{Name} eq 'SubIFD'; 1585 2172 my $subTable; 1586 if ($newInfo->{SubDirectory} ->{TagTable}) {1587 $subTable = GetTagTable($newInfo->{SubDirectory}->{TagTable});2173 if ($newInfo->{SubDirectory}{TagTable}) { 2174 $subTable = Image::ExifTool::GetTagTable($newInfo->{SubDirectory}{TagTable}); 1588 2175 } else { 1589 2176 $subTable = $tagTablePtr; … … 1594 2181 Fixup => new Image::ExifTool::Fixup, 1595 2182 ); 1596 $sourceDir{DirName} = $newInfo->{Groups} ->{1} if $$newInfo{SubIFD};2183 $sourceDir{DirName} = $newInfo->{Groups}{1} if $$newInfo{SubIFD}; 1597 2184 $newValue = $exifTool->WriteDirectory(\%sourceDir, $subTable); 1598 2185 # only add new directory if it isn't empty … … 1614 2201 } else { 1615 2202 # subdirectory goes directly into value buffer 1616 $sourceDir{Fixup} ->{Start} += length($valBuff);2203 $sourceDir{Fixup}{Start} += length($valBuff); 1617 2204 # use Writable to set format, otherwise 'undef' 1618 2205 $newFormName = $$newInfo{Writable}; … … 1635 2222 $newFormat = $oldFormat; # (just in case it changed) 1636 2223 $newFormName = $oldFormName; 2224 # set offset of this entry in the directory so we can update the pointer 2225 # and save block information to copy this large block later 2226 if ($oldImageData) { 2227 $$oldImageData[3] = $newStart + length($dirBuff) + 2; 2228 push @imageData, $oldImageData; 2229 $$origDirInfo{ImageData} = \@imageData; 2230 } 1637 2231 } 1638 2232 if ($newInfo) { … … 1643 2237 my $dataTag = $$newInfo{DataTag}; 1644 2238 # load data for this tag 1645 unless (defined $offsetData{$dataTag}) { 1646 $offsetData{$dataTag} = $exifTool->GetNewValues($dataTag); 2239 unless (defined $offsetData{$dataTag} or $dataTag eq 'LeicaTrailer') { 2240 # prefer tag from Composite table if it exists (otherwise 2241 # PreviewImage data would be taken from Extra tag) 2242 my $compInfo = $Image::ExifTool::Composite{$dataTag}; 2243 $offsetData{$dataTag} = $exifTool->GetNewValues($compInfo || $dataTag); 1647 2244 my $err; 1648 2245 if (defined $offsetData{$dataTag}) { 1649 if ($exifTool->{FILE_TYPE} eq 'JPEG' and 1650 $dataTag ne 'PreviewImage' and length($offsetData{$dataTag}) > 60000) 1651 { 2246 my $len = length $offsetData{$dataTag}; 2247 if ($dataTag eq 'PreviewImage') { 2248 # must set DEL_PREVIEW flag now if preview fit into IFD 2249 $$exifTool{DEL_PREVIEW} = 1 if $len <= 4; 2250 } elsif ($exifTool->{FILE_TYPE} eq 'JPEG' and $len > 60000) { 1652 2251 delete $offsetData{$dataTag}; 1653 2252 $err = "$dataTag not written (too large for JPEG segment)"; … … 1668 2267 if ($$newInfo{MakerNotes}) { 1669 2268 # don't write new makernotes if we are deleting this group 1670 if ($exifTool->{DEL_GROUP} ->{MakerNotes} and1671 ($exifTool->{DEL_GROUP}->{MakerNotes} != 2 or $isNew <= 0))2269 if ($exifTool->{DEL_GROUP}{MakerNotes} and 2270 ($exifTool->{DEL_GROUP}{MakerNotes} != 2 or $isNew <= 0)) 1672 2271 { 1673 2272 if ($isNew <= 0) { … … 1681 2280 # we are writing a whole new maker note block 1682 2281 # --> add fixup information if necessary 1683 my $n ewValueHash = $exifTool->GetNewValueHash($newInfo, $dirName);1684 if ($n ewValueHash and $newValueHash->{MAKER_NOTE_FIXUP}) {2282 my $nvHash = $exifTool->GetNewValueHash($newInfo, $dirName); 2283 if ($nvHash and $nvHash->{MAKER_NOTE_FIXUP}) { 1685 2284 # must clone fixup because we will be shifting it 1686 my $makerFixup = $n ewValueHash->{MAKER_NOTE_FIXUP}->Clone();2285 my $makerFixup = $nvHash->{MAKER_NOTE_FIXUP}->Clone(); 1687 2286 my $valLen = length($valBuff); 1688 2287 $makerFixup->{Start} += $valLen; … … 1692 2291 # update maker notes if possible 1693 2292 my %subdirInfo = ( 1694 Base => $base,1695 DataPt => $valueDataPt,1696 DataPos => $valueDataPos,1697 DataLen => $valueDataLen,2293 Base => $base, 2294 DataPt => $valueDataPt, 2295 DataPos => $valueDataPos, 2296 DataLen => $valueDataLen, 1698 2297 DirStart => $valuePtr, 1699 DirLen => $oldSize, 1700 DirName => 'MakerNotes', 1701 Parent => $dirName, 1702 TagInfo => $newInfo, 1703 RAF => $raf, 2298 DirLen => $oldSize, 2299 DirName => 'MakerNotes', 2300 Name => $$newInfo{Name}, 2301 Parent => $dirName, 2302 TagInfo => $newInfo, 2303 RAF => $raf, 1704 2304 ); 2305 my ($subTable, $subdir, $loc, $writeProc, $notIFD); 1705 2306 if ($$newInfo{SubDirectory}) { 1706 2307 my $sub = $$newInfo{SubDirectory}; … … 1708 2309 $subdirInfo{FixOffsets} = $$sub{FixOffsets}; 1709 2310 $subdirInfo{EntryBased} = $$sub{EntryBased}; 1710 $subdirInfo{NoFixBase} = 1 if $$sub{Base}; 2311 $subdirInfo{NoFixBase} = 1 if defined $$sub{Base}; 2312 $subdirInfo{AutoFix} = $$sub{AutoFix}; 1711 2313 } 1712 2314 # get the proper tag table for these maker notes 1713 my $subTable; 1714 if ($oldInfo and $oldInfo->{SubDirectory}) { 1715 $subTable = $oldInfo->{SubDirectory}->{TagTable}; 2315 if ($oldInfo and $$oldInfo{SubDirectory}) { 2316 $subTable = $$oldInfo{SubDirectory}{TagTable}; 1716 2317 $subTable and $subTable = Image::ExifTool::GetTagTable($subTable); 2318 $writeProc = $$oldInfo{SubDirectory}{WriteProc}; 2319 $notIFD = $$oldInfo{NotIFD}; 1717 2320 } else { 1718 2321 $exifTool->Warn('Internal problem getting maker notes tag table'); 1719 2322 } 1720 2323 $subTable or $subTable = $tagTablePtr; 1721 my $subdir; 1722 # look for IFD-style maker notes 1723 my $loc = Image::ExifTool::MakerNotes::LocateIFD($exifTool,\%subdirInfo); 2324 if ($writeProc and 2325 $writeProc eq \&Image::ExifTool::MakerNotes::WriteUnknownOrPreview and 2326 $oldValue =~ /^\xff\xd8\xff/) 2327 { 2328 $loc = 0; 2329 } elsif (not $notIFD) { 2330 # look for IFD-style maker notes 2331 $loc = Image::ExifTool::MakerNotes::LocateIFD($exifTool,\%subdirInfo); 2332 } 1724 2333 if (defined $loc) { 1725 2334 # we need fixup data for this subdirectory 1726 2335 $subdirInfo{Fixup} = new Image::ExifTool::Fixup; 1727 2336 # rewrite maker notes 1728 $subdir = $exifTool->WriteDirectory(\%subdirInfo, $subTable );2337 $subdir = $exifTool->WriteDirectory(\%subdirInfo, $subTable, $writeProc); 1729 2338 } elsif ($$subTable{PROCESS_PROC} and 1730 2339 $$subTable{PROCESS_PROC} eq \&Image::ExifTool::ProcessBinaryData) 1731 2340 { 1732 my $sub = $ oldInfo->{SubDirectory};2341 my $sub = $$oldInfo{SubDirectory}; 1733 2342 if (defined $$sub{Start}) { 1734 2343 #### eval Start ($valuePtr) … … 1742 2351 # rewrite maker notes 1743 2352 $subdir = $exifTool->WriteDirectory(\%subdirInfo, $subTable); 1744 } else { 1745 $exifTool->Warn('Maker notes could not be parsed',1); 2353 } elsif (not $notIFD) { 2354 my $msg = 'Maker notes could not be parsed'; 2355 if ($$exifTool{FILE_TYPE} eq 'JPEG') { 2356 $exifTool->Warn($msg, 1); 2357 } else { 2358 $exifTool->Error($msg, 1); 2359 } 1746 2360 } 1747 2361 if (defined $subdir) { … … 1763 2377 # remove all but PreviewImage fixup (since others shouldn't change) 1764 2378 foreach (keys %{$makerFixup->{Pointers}}) { 1765 /_PreviewImage$/ or delete $makerFixup->{Pointers} ->{$_};2379 /_PreviewImage$/ or delete $makerFixup->{Pointers}{$_}; 1766 2380 } 1767 2381 # zero pointer so we can see how it gets shifted later … … 1774 2388 $previewInfo->{Relative} = 1; 1775 2389 } 2390 # don't shift anything if relative flag set to zero (Pentax patch) 1776 2391 } elsif (not defined $subdirInfo{Relative}) { 1777 # don't shift anything if relative flag set to zero (Pentax patch) 2392 # shift offset base if shifted in the original image or if FixBase 2393 # was used, but be careful of automatic FixBase with negative shifts 2394 # since they may lead to negative (invalid) offsets (casio_edit_problem.jpg) 1778 2395 my $baseShift = $base - $subdirInfo{Base}; 2396 if ($subdirInfo{AutoFix}) { 2397 $baseShift = 0; 2398 } elsif ($subdirInfo{FixBase} and $baseShift < 0 and 2399 # allow negative base shift if offsets are bigger (PentaxOptioWP.jpg) 2400 (not $subdirInfo{MinOffset} or $subdirInfo{MinOffset} + $baseShift < 0)) 2401 { 2402 my $fixBase = $exifTool->Options('FixBase'); 2403 if (not defined $fixBase) { 2404 my $str = $exifTool->Options('IgnoreMinorErrors') ? 'ignored' : 'fix or ignore?'; 2405 $exifTool->Error("MakerNotes offsets may be incorrect ($str)", 1); 2406 } elsif ($fixBase eq '') { 2407 $exifTool->Warn('Fixed incorrect MakerNotes offsets'); 2408 $baseShift = 0; 2409 } 2410 } 1779 2411 $makerFixup->{Start} += $valLen + $loc; 1780 2412 $makerFixup->{Shift} += $baseShift; 2413 # permanently fix makernote offset errors 2414 $makerFixup->{Shift} += $subdirInfo{FixedBy} || 0; 1781 2415 push @valFixups, $makerFixup; 1782 2416 if ($previewInfo and not $previewInfo->{NoBaseShift}) { … … 1800 2434 # rewrite existing sub IFD's 1801 2435 # 1802 my $subdirName = $newInfo->{Groups}->{1} || $$newInfo{Name}; 2436 my $subTable = $tagTablePtr; 2437 if ($$subdir{TagTable}) { 2438 $subTable = Image::ExifTool::GetTagTable($$subdir{TagTable}); 2439 } 2440 # determine directory name for this IFD 2441 my $subdirName = $newInfo->{Groups}{1} || $$newInfo{Name}; 2442 # all makernotes directory names must be 'MakerNotes' 2443 $subdirName = 'MakerNotes' if $subTable->{GROUPS}{0} eq 'MakerNotes'; 1803 2444 # must handle sub-IFD's specially since the values 1804 2445 # are actually offsets to subdirectories 1805 2446 unless ($readCount) { # can't have zero count 1806 return undef if $exifTool->Error("$ dirName entry $index has zero count", 1);2447 return undef if $exifTool->Error("$name entry $index has zero count", 1); 1807 2448 next; 1808 2449 } … … 1817 2458 my $subdirBase = $base; 1818 2459 if ($$subdir{Base}) { 1819 my $start = $subdirStart + $ valueDataPos;1820 #### eval Base ($start )2460 my $start = $subdirStart + $dataPos; 2461 #### eval Base ($start,$base) 1821 2462 $subdirBase += eval $$subdir{Base}; 1822 2463 } 2464 # add IFD number if more than one 2465 $subdirName =~ s/\d*$/$i/ if $i; 1823 2466 my %subdirInfo = ( 1824 Base => $subdirBase,1825 DataPt => $dataPt,1826 DataPos => $dataPos - $subdirBase + $base,1827 DataLen => $dataLen,2467 Base => $subdirBase, 2468 DataPt => $dataPt, 2469 DataPos => $dataPos - $subdirBase + $base, 2470 DataLen => $dataLen, 1828 2471 DirStart => $subdirStart, 1829 DirName => $subdirName . ($i ? $i : ''), 1830 Parent => $dirName, 1831 Fixup => new Image::ExifTool::Fixup, 1832 RAF => $raf, 2472 DirName => $subdirName, 2473 Name => $$newInfo{Name}, 2474 TagInfo => $newInfo, 2475 Parent => $dirName, 2476 Fixup => new Image::ExifTool::Fixup, 2477 RAF => $raf, 2478 Subdir => $subdir, 2479 # set ImageData only for 1st level SubIFD's 2480 ImageData=> $imageDataFlag eq 'Main' ? 'SubIFD' : undef, 1833 2481 ); 1834 # read IFD from file if necessary 2482 # pass on header pointer only for certain sub IFD's 2483 $subdirInfo{HeaderPtr} = $$dirInfo{HeaderPtr} if $$newInfo{SubIFD} == 2; 2484 if ($$subdir{RelativeBase}) { 2485 # apply one-time fixup if offsets are relative (Sony IDC hack) 2486 delete $subdirInfo{Fixup}; 2487 delete $subdirInfo{ImageData}; 2488 } 2489 # is the subdirectory outside our current data? 1835 2490 if ($subdirStart < 0 or $subdirStart + 2 > $dataLen) { 1836 my ($buff, $buf2, $subSize); 1837 unless ($raf and $raf->Seek($pt + $base, 0) and 1838 $raf->Read($buff,2) == 2 and 1839 $subSize = 12 * Get16u(\$buff, 0) and 1840 $raf->Read($buf2,$subSize+4) >= $subSize) 1841 { 1842 if (defined $subSize and not $subSize) { 1843 return undef if $exifTool->Error("$subdirName IFD has zero entries", 1); 1844 next Entry; 2491 if ($raf) { 2492 # reset SubDirectory buffer (we will load it later) 2493 my $buff = ''; 2494 $subdirInfo{DataPt} = \$buff; 2495 $subdirInfo{DataLen} = 0; 2496 } else { 2497 my @err = ("Can't read $subdirName data", $inMakerNotes); 2498 if ($$subTable{VARS} and $subTable->{VARS}{MINOR_ERRORS}) { 2499 $exifTool->Warn($err[0] . '. Ignored.'); 2500 } elsif ($exifTool->Error(@err)) { 2501 return undef; 1845 2502 } 1846 return undef if $exifTool->Error("Can't read $subdirName data", $inMakerNotes); 1847 next Entry; 2503 next Entry; # don't write this directory 1848 2504 } 1849 $buff .= $buf2;1850 # change subdirectory information to data we just read1851 $subdirInfo{DataPt} = \$buff;1852 $subdirInfo{DirStart} = 0;1853 $subdirInfo{DataPos} = $pt;1854 $subdirInfo{DataLen} = length $buff;1855 # only account for nextIFD pointer if we will use it1856 $subSize += 4 if length($buff)==$subSize+6 and1857 ($$newInfo{Name} eq 'SubIFD' or $buff =~ /\0{4}$/);1858 UpdateTiffEnd($exifTool, $pt+$base+2+$subSize);1859 2505 } 1860 my $subTable = $tagTablePtr; 1861 if ($$subdir{TagTable}) { 1862 $subTable = GetTagTable($$subdir{TagTable}); 2506 my $subdirData = $exifTool->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc}); 2507 unless (defined $subdirData) { 2508 # WriteDirectory should have issued an error, but check just in case 2509 $exifTool->Error("Error writing $subdirName") unless $$exifTool{VALUE}{Error}; 2510 return undef; 1863 2511 } 1864 my $subdirData = $exifTool->WriteDirectory(\%subdirInfo, $subTable); 1865 return undef unless defined $subdirData; 1866 next unless length($subdirData); 2512 unless (length $subdirData) { 2513 next unless $inMakerNotes; 2514 # don't delete MakerNote Sub-IFD's, write empty IFD instead 2515 $subdirData = "\0" x 6; 2516 # reset SubIFD ImageData and Fixup just to be safe 2517 delete $subdirInfo{ImageData}; 2518 delete $subdirInfo{Fixup}; 2519 } 2520 # handle data blocks that we will transfer later 2521 if (ref $subdirInfo{ImageData}) { 2522 push @imageData, @{$subdirInfo{ImageData}}; 2523 $$origDirInfo{ImageData} = \@imageData; 2524 } 1867 2525 # temporarily set value to subdirectory index 1868 2526 # (will set to actual offset later when we know what it is) … … 1878 2536 # add to list of subdirectories we will append later 1879 2537 push @subdirs, { 1880 DataPt => \$subdirData, 1881 Table => $subTable, 1882 Fixup => $subdirInfo{Fixup}, 1883 Offset => $offset, 1884 Where => $where, 2538 DataPt => \$subdirData, 2539 Table => $subTable, 2540 Fixup => $subdirInfo{Fixup}, 2541 Offset => $offset, 2542 Where => $where, 2543 ImageData => $subdirInfo{ImageData}, 1885 2544 }; 1886 2545 ++$writeCount; # count number of subdirs written … … 1890 2549 # a directory and only one remains 1891 2550 if ($writeCount < $readCount and $writeCount == 1) { 1892 $subdirs[-1] ->{Where} = 'dirBuff';1893 $subdirs[-1] ->{Offset} = length($dirBuff) + 8;2551 $subdirs[-1]{Where} = 'dirBuff'; 2552 $subdirs[-1]{Offset} = length($dirBuff) + 8; 1894 2553 } 1895 2554 # set new format to int32u for IFD … … 1916 2575 if ($$subdir{Base}) { 1917 2576 my $start = $subdirStart + $valueDataPos; 1918 #### eval Base ($start )2577 #### eval Base ($start,$base) 1919 2578 $subdirBase += eval $$subdir{Base}; 1920 2579 } 1921 2580 my $subFixup = new Image::ExifTool::Fixup; 1922 2581 my %subdirInfo = ( 1923 Base => $subdirBase,1924 DataPt => $valueDataPt,1925 DataPos => $valueDataPos - $subdirBase + $base,1926 DataLen => $valueDataLen,2582 Base => $subdirBase, 2583 DataPt => $valueDataPt, 2584 DataPos => $valueDataPos - $subdirBase + $base, 2585 DataLen => $valueDataLen, 1927 2586 DirStart => $subdirStart, 1928 DirName => $$subdir{DirName}, 1929 DirLen => $oldSize, 1930 Parent => $dirName, 1931 Fixup => $subFixup, 1932 RAF => $raf, 2587 DirName => $$subdir{DirName}, 2588 DirLen => $oldSize, 2589 Parent => $dirName, 2590 Fixup => $subFixup, 2591 RAF => $raf, 2592 TagInfo => $newInfo, 1933 2593 ); 1934 my $subTable = GetTagTable($$subdir{TagTable}); 1935 $newValue = $exifTool->WriteDirectory(\%subdirInfo, $subTable); 2594 unless ($oldSize) { 2595 # replace with dummy data if empty to prevent WriteDirectory 2596 # routines from accessing data they shouldn't 2597 my $tmp = ''; 2598 $subdirInfo{DataPt} = \$tmp; 2599 $subdirInfo{DataLen} = 0; 2600 $subdirInfo{DirStart} = 0; 2601 $subdirInfo{DataPos} += $subdirStart; 2602 } 2603 my $subTable = Image::ExifTool::GetTagTable($$subdir{TagTable}); 2604 my $oldOrder = GetByteOrder(); 2605 SetByteOrder($$subdir{ByteOrder}) if $$subdir{ByteOrder}; 2606 $newValue = $exifTool->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc}); 2607 SetByteOrder($oldOrder); 1936 2608 if (defined $newValue) { 1937 2609 my $hdrLen = $subdirStart - $valuePtr; … … 1946 2618 return undef; 1947 2619 } 1948 next unless length $$newValuePt; 2620 unless (length $$newValuePt) { 2621 # don't delete a previously empty makernote directory 2622 next if $oldSize or not $inMakerNotes; 2623 } 1949 2624 if ($subFixup->{Pointers} and $subdirInfo{Base} == $base) { 1950 2625 $subFixup->{Start} += length $valBuff; … … 1964 2639 # must decide now if we will write CanonVRD information 1965 2640 my $hasVRD; 1966 if ($exifTool->{NEW_VALUE} ->{$Image::ExifTool::Extra{CanonVRD}}) {2641 if ($exifTool->{NEW_VALUE}{$Image::ExifTool::Extra{CanonVRD}}) { 1967 2642 # adding or deleting as a block 1968 2643 $hasVRD = $exifTool->GetNewValues('CanonVRD') ? 1 : 0; 1969 } elsif ($exifTool->{DEL_GROUP} ->{CanonVRD} or1970 $exifTool->{DEL_GROUP} ->{Trailer})2644 } elsif ($exifTool->{DEL_GROUP}{CanonVRD} or 2645 $exifTool->{DEL_GROUP}{Trailer}) 1971 2646 { 1972 2647 $hasVRD = 0; # deleting as a group … … 1982 2657 $newValuePt = \$newValue; 1983 2658 } 2659 } elsif ($dataTag eq 'OriginalDecisionData') { 2660 # handle Canon OriginalDecisionData (no associated length tag) 2661 # - I'm going out of my way here to preserve data which is 2662 # invalidated anyway by our edits 2663 my $odd; 2664 my $oddInfo = $Image::ExifTool::Composite{OriginalDecisionData}; 2665 if ($oddInfo and $exifTool->{NEW_VALUE}{$oddInfo}) { 2666 $odd = $exifTool->GetNewValues($dataTag); 2667 if ($verbose > 1) { 2668 print $out " - $dirName:$dataTag\n" if $$newValuePt ne "\0\0\0\0"; 2669 print $out " + $dirName:$dataTag\n" if $odd; 2670 } 2671 ++$exifTool->{CHANGED}; 2672 } elsif ($$newValuePt ne "\0\0\0\0") { 2673 if (length($$newValuePt) == 4) { 2674 require Image::ExifTool::Canon; 2675 my $offset = Get32u($newValuePt,0); 2676 # absolute offset in JPEG images only 2677 $offset += $base unless $$exifTool{FILE_TYPE} eq 'JPEG'; 2678 $odd = Image::ExifTool::Canon::ReadODD($exifTool, $offset); 2679 $odd = $$odd if ref $odd; 2680 } else { 2681 $exifTool->Error("Invalid $$newInfo{Name}",1); 2682 } 2683 } 2684 if ($odd) { 2685 my $newOffset = length($valBuff); 2686 # (ODD offset is absolute in JPEG, so add base offset!) 2687 $newOffset += $base if $$exifTool{FILE_TYPE} eq 'JPEG'; 2688 $newValue = Set32u($newOffset); 2689 $dirFixup->AddFixup(length($dirBuff) + 8, $dataTag); 2690 $valBuff .= $odd; # add original decision data 2691 } else { 2692 $newValue = "\0\0\0\0"; 2693 } 2694 $newValuePt = \$newValue; 1984 2695 } else { 1985 2696 my $offsetInfo = $offsetInfo[$ifd]; … … 1987 2698 my @vals; 1988 2699 if ($isNew <= 0) { 2700 my $oldOrder = GetByteOrder(); 2701 # Minolta A200 stores these in the wrong byte order! 2702 SetByteOrder($$newInfo{ByteOrder}) if $$newInfo{ByteOrder}; 1989 2703 @vals = ReadValue(\$oldValue, 0, $readFormName, $readCount, $oldSize); 2704 SetByteOrder($oldOrder); 1990 2705 } 1991 2706 # only support int32 pointers (for now) 1992 2707 if ($formatSize[$newFormat] != 4 and $$newInfo{IsOffset}) { 1993 die "Internal error (Offset not int32)" if $isNew > 0;1994 die "Wrong count!" if $newCount != $readCount;2708 $isNew > 0 and warn("Internal error (Offset not int32)"), return undef; 2709 $newCount != $readCount and warn("Wrong count!"), return undef; 1995 2710 # change to int32 1996 2711 $newFormName = 'int32u'; 1997 2712 $newFormat = $formatNumber{$newFormName}; 1998 2713 $newValue = WriteValue(join(' ',@vals), $newFormName, $newCount); 1999 die "Internal error writing offsets\n" unless defined $newValue; 2714 unless (defined $newValue) { 2715 warn "Internal error writing offsets for $$newInfo{Name}\n"; 2716 return undef; 2717 } 2000 2718 } 2001 2719 $offsetInfo or $offsetInfo = $offsetInfo[$ifd] = { }; … … 2011 2729 } elsif ($$newInfo{DataMember}) { 2012 2730 2013 # save any necessary data members (CameraMake, CameraModel) 2014 $exifTool->{$$newInfo{DataMember}} = $$newValuePt; 2731 # save any necessary data members (Make, Model, etc) 2732 my $formatStr = $newFormName; 2733 my $count = $newCount; 2734 # change to specified format if necessary 2735 if ($$newInfo{Format} and $$newInfo{Format} ne $formatStr) { 2736 $formatStr = $$newInfo{Format}; 2737 my $format = $formatNumber{$formatStr}; 2738 # adjust number of items for new format size 2739 $count = int(length($$newValuePt) / $formatSize[$format]) if $format; 2740 } 2741 my $val = ReadValue($newValuePt,0,$formatStr,$count,length($$newValuePt)); 2742 my $conv = $$newInfo{RawConv}; 2743 if ($conv) { 2744 # let the RawConv store the (possibly converted) data member 2745 if (ref $conv eq 'CODE') { 2746 &$conv($val, $exifTool); 2747 } else { 2748 my ($self, $tag, $taginfo) = ($exifTool, $$newInfo{Name}, $newInfo); 2749 #### eval RawConv ($self, $val, $tag, $tagInfo) 2750 eval $conv; 2751 } 2752 } else { 2753 $$exifTool{$$newInfo{DataMember}} = $val; 2754 } 2015 2755 } 2016 2756 } … … 2036 2776 $offsetVal = Set32u(length $valBuff); 2037 2777 } 2038 my $dataTag; 2039 if ($newInfo and $$newInfo{DataTag}) { 2040 $dataTag = $$newInfo{DataTag}; 2041 if ($dataTag eq 'PreviewImage' and $exifTool->{FILE_TYPE} eq 'JPEG') { 2778 my ($dataTag, $putFirst); 2779 ($dataTag, $putFirst) = @$newInfo{'DataTag','PutFirst'} if $newInfo; 2780 if ($dataTag) { 2781 if ($dataTag eq 'PreviewImage' and ($exifTool->{FILE_TYPE} eq 'JPEG' or 2782 $$exifTool{GENERATE_PREVIEW_INFO})) 2783 { 2042 2784 # hold onto the PreviewImage until we can determine if it fits 2043 2785 $exifTool->{PREVIEW_INFO} or $exifTool->{PREVIEW_INFO} = { }; 2044 $exifTool->{PREVIEW_INFO}->{Data} = $$newValuePt; 2045 if ($$newInfo{Name} eq 'PreviewImage') { 2046 $exifTool->{PREVIEW_INFO}->{IsValue} = 1; 2047 } 2786 $exifTool->{PREVIEW_INFO}{Data} = $$newValuePt; 2787 $exifTool->{PREVIEW_INFO}{ChangeBase} = 1 if $$newInfo{ChangeBase}; 2048 2788 if ($$newInfo{IsOffset} and $$newInfo{IsOffset} eq '2') { 2049 $exifTool->{PREVIEW_INFO}->{NoBaseShift} = 1; 2050 } 2789 $exifTool->{PREVIEW_INFO}{NoBaseShift} = 1; 2790 } 2791 # use original preview size if we will attempt to load it later 2792 $newCount = $oldCount if $$newValuePt eq 'LOAD_PREVIEW'; 2051 2793 $$newValuePt = ''; 2794 } elsif ($dataTag eq 'LeicaTrailer' and $$exifTool{LeicaTrailer}) { 2795 $$newValuePt = ''; 2052 2796 } 2053 2797 } 2054 $valBuff .= $$newValuePt; # add value data to buffer2055 # must save a fixup pointer for every pointer in the directory2056 if ($entryBased) {2057 $ entryBasedFixup or $entryBasedFixup = new Image::ExifTool::Fixup;2058 $ entryBasedFixup->AddFixup(length($dirBuff) + 8, $dataTag);2798 if ($putFirst and $$dirInfo{HeaderPtr}) { 2799 my $hdrPtr = $$dirInfo{HeaderPtr}; 2800 # place this value immediately after the TIFF header 2801 $offsetVal = Set32u(length $$hdrPtr); 2802 $$hdrPtr .= $$newValuePt; 2059 2803 } else { 2060 $dirFixup->AddFixup(length($dirBuff) + 8, $dataTag); 2804 $valBuff .= $$newValuePt; # add value data to buffer 2805 # must save a fixup pointer for every pointer in the directory 2806 if ($entryBased) { 2807 $entryBasedFixup or $entryBasedFixup = new Image::ExifTool::Fixup; 2808 $entryBasedFixup->AddFixup(length($dirBuff) + 8, $dataTag); 2809 } else { 2810 $dirFixup->AddFixup(length($dirBuff) + 8, $dataTag); 2811 } 2061 2812 } 2062 2813 } else { … … 2072 2823 if (defined $$mandatory{$newID}) { 2073 2824 # values must correspond to mandatory values 2074 my $mandVal = WriteValue($$mandatory{$newID}, $newFormName, $newCount); 2825 my $form = $$newInfo{Format} || $newFormName; 2826 my $mandVal = WriteValue($$mandatory{$newID}, $form, $newCount); 2075 2827 if (defined $mandVal and $mandVal eq $$newValuePt) { 2076 2828 ++$allMandatory; # count mandatory tags … … 2082 2834 } 2083 2835 } 2836 if ($ignoreCount) { 2837 my $y = $ignoreCount > 1 ? 'ies' : 'y'; 2838 $exifTool->Warn("Removed $ignoreCount invalid entr$y from $name", 1); 2839 } 2840 if ($fixCount) { 2841 my $s = $fixCount > 1 ? 's' : ''; 2842 $exifTool->Warn("Fixed invalid count$s for $fixCount $name tag$s", 1); 2843 } 2084 2844 #.............................................................................. 2085 2845 # write directory counts and nextIFD pointer and add value data to end of IFD 2086 2846 # 2847 # determine now if there is or will be another IFD after this one 2848 my $nextIfdOffset; 2849 if ($dirEnd + 4 <= $dataLen) { 2850 $nextIfdOffset = Get32u($dataPt, $dirEnd); 2851 } else { 2852 $nextIfdOffset = 0; 2853 } 2854 my $isNextIFD = ($$dirInfo{Multi} and ($nextIfdOffset or 2855 # account for the case where we will create the next IFD 2856 ($dirName eq 'IFD0' and $exifTool->{ADD_DIRS}{'IFD1'}))); 2087 2857 # calculate number of entries in new directory 2088 2858 my $newEntries = length($dirBuff) / 12; 2089 # delete entire directory if only mandatory tags remain 2090 if ($newEntries < $numEntries and $allMandatory) { 2859 # delete entire directory if we deleted a tag and only mandatory tags remain or we 2860 # attempted to create a directory with only mandatory tags and there is no nextIFD 2861 if ($allMandatory and not $isNextIFD and ($newEntries < $numEntries or $numEntries == 0)) { 2091 2862 $newEntries = 0; 2092 2863 $dirBuff = ''; … … 2095 2866 ++$deleteAll if defined $deleteAll; 2096 2867 $verbose > 1 and print $out " - $allMandatory mandatory tag(s)\n"; 2868 $exifTool->{CHANGED} -= $addMandatory; # didn't change these after all 2097 2869 } 2098 2870 if ($ifd and not $newEntries) { … … 2127 2899 my $subdir; 2128 2900 foreach $subdir (@subdirs) { 2129 my $pos = length($newData); # position of subdirectory in data 2130 my $subdirFixup = $subdir->{Fixup}; 2131 $subdirFixup->{Start} += $pos; 2132 $fixup->AddFixup($subdirFixup); 2133 $newData .= ${$subdir->{DataPt}}; # add subdirectory to our data 2134 undef ${$subdir->{DataPt}}; # free memory now 2901 my $len = length($newData); # position of subdirectory in data 2902 my $subdirFixup = $$subdir{Fixup}; 2903 if ($subdirFixup) { 2904 $$subdirFixup{Start} += $len; 2905 $fixup->AddFixup($subdirFixup); 2906 } 2907 my $imageData = $$subdir{ImageData}; 2908 my $blockSize = 0; 2909 # must also update start position for ImageData fixups 2910 if (ref $imageData) { 2911 my $blockInfo; 2912 foreach $blockInfo (@$imageData) { 2913 my ($pos, $size, $pad, $entry, $subFix) = @$blockInfo; 2914 if ($subFix) { 2915 $$subFix{Start} += $len; 2916 # save expected image data offset for calculating shift later 2917 $$subFix{BlockLen} = length(${$$subdir{DataPt}}) + $blockSize; 2918 } 2919 $blockSize += $size + $pad; 2920 } 2921 } 2922 $newData .= ${$$subdir{DataPt}}; # add subdirectory to our data 2923 undef ${$$subdir{DataPt}}; # free memory now 2135 2924 # set the pointer 2136 my $offset = $ subdir->{Offset};2925 my $offset = $$subdir{Offset}; 2137 2926 # if offset is in valBuff, it was added to the end of dirBuff 2138 2927 # (plus 4 bytes for nextIFD pointer) 2139 $offset += length($dirBuff) + 4 if $ subdir->{Where} eq 'valBuff';2928 $offset += length($dirBuff) + 4 if $$subdir{Where} eq 'valBuff'; 2140 2929 $offset += $newStart + 2; # get offset in newData 2141 2930 # check to be sure we got the right offset 2142 2931 unless (Get32u(\$newData, $offset) == 0xfeedf00d) { 2143 $exifTool->Error("Internal error while rewriting $ dirName");2932 $exifTool->Error("Internal error while rewriting $name"); 2144 2933 return undef; 2145 2934 } 2146 2935 # set the offset to the subdirectory data 2147 Set32u($ pos, \$newData, $offset);2936 Set32u($len, \$newData, $offset); 2148 2937 $fixup->AddFixup($offset); # add fixup for this offset in newData 2149 2938 } … … 2163 2952 } 2164 2953 # stop if no next IFD pointer 2165 last unless $$dirInfo{Multi}; # stop unless scanning for multiple IFD's 2166 my $offset; 2167 if ($dirStart + $len + 4 <= $dataLen) { 2168 $offset = Get32u($dataPt, $dirStart + $len); 2169 } else { 2170 $offset = 0; 2171 } 2172 if ($offset) { 2954 last unless $isNextIFD; # stop unless scanning for multiple IFD's 2955 if ($nextIfdOffset) { 2173 2956 # continue with next IFD 2174 $dirStart = $ offset - $dataPos;2957 $dirStart = $nextIfdOffset - $dataPos; 2175 2958 } else { 2176 2959 # create IFD1 if necessary 2177 last unless $dirName eq 'IFD0' and $exifTool->{ADD_DIRS}->{'IFD1'};2178 2960 $verbose and print $out " Creating IFD1\n"; 2179 2961 my $ifd1 = "\0" x 2; # empty IFD1 data (zero entry count) … … 2183 2965 } 2184 2966 # increment IFD name 2185 $dirName =~ s/(\d+)$//;2186 $dirName .= ($1 || 0)+ 1;2187 $ exifTool->{DIR_NAME}= $dirName;2188 next unless $ offset;2967 my $ifdNum = $dirName =~ s/(\d+)$// ? $1 : 0; 2968 $dirName .= $ifdNum + 1; 2969 $$exifTool{DIR_NAME} = $$exifTool{PATH}[-1] = $dirName; 2970 next unless $nextIfdOffset; 2189 2971 2190 2972 # guard against writing the same directory twice 2191 my $addr = $ offset + $base;2192 if ($exifTool->{PROCESSED} ->{$addr}) {2193 $exifTool->Error("$ dirName pointer references previous $exifTool->{PROCESSED}->{$addr} directory", 1);2973 my $addr = $nextIfdOffset + $base; 2974 if ($exifTool->{PROCESSED}{$addr}) { 2975 $exifTool->Error("$name pointer references previous $exifTool->{PROCESSED}{$addr} directory", 1); 2194 2976 last; 2195 2977 } 2196 $exifTool->{PROCESSED} ->{$addr} = $dirName;2978 $exifTool->{PROCESSED}{$addr} = $name; 2197 2979 2198 2980 if ($dirName eq 'SubIFD1' and not ValidateIFD($dirInfo, $dirStart)) { … … 2204 2986 last; # don't write bad IFD 2205 2987 } 2206 if ($exifTool->{DEL_GROUP} ->{$dirName}) {2988 if ($exifTool->{DEL_GROUP}{$dirName}) { 2207 2989 $verbose and print $out " Deleting $dirName\n"; 2208 2990 $raf and $exifTool->Error("Deleting $dirName also deletes subsequent" . 2209 2991 " IFD's and possibly image data", 1); 2210 2992 ++$exifTool->{CHANGED}; 2211 if ($exifTool->{DEL_GROUP} ->{$dirName} == 2 and2212 $exifTool->{ADD_DIRS} ->{$dirName})2993 if ($exifTool->{DEL_GROUP}{$dirName} == 2 and 2994 $exifTool->{ADD_DIRS}{$dirName}) 2213 2995 { 2214 2996 my $emptyIFD = "\0" x 2; # start with empty IFD … … 2220 3002 } 2221 3003 } else { 2222 $verbose and print $out " Rewriting $ dirName\n";3004 $verbose and print $out " Rewriting $name\n"; 2223 3005 } 2224 3006 } … … 2228 3010 $fixup->ApplyFixup(\$newData); 2229 3011 # 3012 # determine total block size for deferred data 3013 # 3014 my $numBlocks = scalar @imageData; # save this so we scan only existing blocks later 3015 my $blockSize = 0; # total size of blocks to copy later 3016 my $blockInfo; 3017 foreach $blockInfo (@imageData) { 3018 my ($pos, $size, $pad) = @$blockInfo; 3019 $blockSize += $size + $pad; 3020 } 3021 # 2230 3022 # copy over image data for IFD's, starting with the last IFD first 2231 3023 # 2232 my @imageData; # image data blocks if requested2233 my $blockSize = 0; # total size of blocks to copy later2234 3024 if (@offsetInfo) { 2235 my @writeLater; # write image data last 3025 my $ttwLen; # length of MRW TTW segment 3026 my @writeLater; # write image data last 2236 3027 for ($ifd=$#offsetInfo; $ifd>=-1; --$ifd) { 2237 3028 # build list of offsets to process … … 2239 3030 if ($ifd >= 0) { 2240 3031 my $offsetInfo = $offsetInfo[$ifd] or next; 3032 # patch Panasonic RAW/RW2 StripOffsets/StripByteCounts if necessary 3033 my $stripOffsets = $$offsetInfo{0x111}; 3034 if ($stripOffsets and $$stripOffsets[0]{PanasonicHack}) { 3035 require Image::ExifTool::PanasonicRaw; 3036 my $err = Image::ExifTool::PanasonicRaw::PatchRawDataOffset($offsetInfo, $raf, $ifd); 3037 $err and $exifTool->Error($err); 3038 } 2241 3039 my $tagID; 2242 3040 # loop through all tags in reverse order so we save thumbnail 2243 3041 # data before main image data if both exist in the same IFD 2244 3042 foreach $tagID (reverse sort keys %$offsetInfo) { 2245 my $tagInfo = $offsetInfo->{$tagID} ->[0];3043 my $tagInfo = $offsetInfo->{$tagID}[0]; 2246 3044 next unless $$tagInfo{IsOffset}; # handle byte counts with offsets 2247 3045 my $sizeInfo = $offsetInfo->{$$tagInfo{OffsetPair}}; … … 2249 3047 my $dataTag = $$tagInfo{DataTag}; 2250 3048 # write TIFF image data (strips or tiles) later if requested 2251 if ($raf and defined $_[1]->{ImageData} and 2252 ($tagID == 0x111 or $tagID == 0x144) and 3049 if ($raf and defined $$origDirInfo{ImageData} and 3050 ($tagID == 0x111 or $tagID == 0x144 or 3051 # also defer writing of other big data such as JpgFromRaw in NEF 3052 ($$sizeInfo[3][0] and 3053 # (calculate approximate combined size of all blocks) 3054 $$sizeInfo[3][0] * scalar(@{$$sizeInfo[3]}) > 1000000)) and 3055 # but don't defer writing if replacing with new value 2253 3056 (not defined $dataTag or not defined $offsetData{$dataTag})) 2254 3057 { … … 2268 3071 # must be the same number of offset and byte count values 2269 3072 unless ($count == $count2) { 2270 $exifTool->Error("Offset /byteCounts disagree on count for $$tagInfo{Name}");3073 $exifTool->Error("Offsets/ByteCounts disagree on count for $$tagInfo{Name}"); 2271 3074 return undef; 2272 3075 } … … 2281 3084 } 2282 3085 # get offset base and data pos (abnormal for some preview images) 2283 my ($dbase, $dpos );3086 my ($dbase, $dpos, $wrongBase, $subIfdDataFixup); 2284 3087 if ($$tagInfo{IsOffset} eq '2') { 2285 3088 $dbase = $firstBase; … … 2289 3092 $dpos = $dataPos; 2290 3093 } 3094 # use different base if necessary for some offsets (Minolta A200) 3095 if ($$tagInfo{WrongBase}) { 3096 my $self = $exifTool; 3097 #### eval WrongBase ($self) 3098 $wrongBase = eval $$tagInfo{WrongBase} || 0; 3099 $dbase += $wrongBase; 3100 $dpos -= $wrongBase; 3101 } else { 3102 $wrongBase = 0; 3103 } 3104 my $oldOrder = GetByteOrder(); 3105 my $dataTag = $$tagInfo{DataTag}; 3106 # use different byte order for values of this offset pair if required (Minolta A200) 3107 SetByteOrder($$tagInfo{ByteOrder}) if $$tagInfo{ByteOrder}; 2291 3108 # transfer the data referenced by all offsets of this tag 2292 3109 for ($n=0; $n<$count; ++$n) { 2293 my $oldEnd;3110 my ($oldEnd, $size); 2294 3111 if (@$oldOffset and @$oldSize) { 2295 3112 # calculate end offset of this block … … 2300 3117 my $offsetPos = $offsets + $n * 4; 2301 3118 my $byteCountPos = $byteCounts + $n * $formatSize[$format]; 2302 my $size = ReadValue(\$newData, $byteCountPos, $formatStr, 1, 4); 2303 my $offset = Get32u(\$newData, $offsetPos) - $dpos; 3119 if ($$tagInfo{PanasonicHack}) { 3120 # use actual raw data length (may be different than StripByteCounts!) 3121 $size = $$oldSize[$n]; 3122 } else { 3123 # use size of new data 3124 $size = ReadValue(\$newData, $byteCountPos, $formatStr, 1, 4); 3125 } 3126 my $offset = $$oldOffset[$n]; 3127 if (defined $offset) { 3128 $offset -= $dpos; 3129 } elsif ($size != 0xfeedfeed) { 3130 $exifTool->Error('Internal error (no offset)'); 3131 return undef; 3132 } 3133 my $newOffset = length($newData) - $wrongBase; 2304 3134 my $buff; 2305 3135 # look for 'feed' code to use our new data 2306 3136 if ($size == 0xfeedfeed) { 2307 my $dataTag = $$tagInfo{DataTag};2308 3137 unless (defined $dataTag) { 2309 3138 $exifTool->Error("No DataTag defined for $$tagInfo{Name}"); … … 2332 3161 $oldEnd != $$oldOffset[$n+1]); 2333 3162 # preserve original image padding if specified 2334 if ($ _[1]->{PreserveImagePadding} and $n+1 < $count and3163 if ($$origDirInfo{PreserveImagePadding} and $n+1 < $count and 2335 3164 $oldEnd and $$oldOffset[$n+1] > $oldEnd) 2336 3165 { … … 2339 3168 # copy data later 2340 3169 push @imageData, [$offset+$dbase+$dpos, $size, $pad]; 3170 $newOffset += $blockSize; # data comes after other deferred data 3171 # create fixup for SubIFD ImageData 3172 if ($imageDataFlag eq 'SubIFD' and not $subIfdDataFixup) { 3173 $subIfdDataFixup = new Image::ExifTool::Fixup; 3174 $imageData[-1][4] = $subIfdDataFixup; 3175 } 2341 3176 $size += $pad; # account for pad byte if necessary 2342 3177 # return ImageData list 2343 $ _[1]->{ImageData} = \@imageData;3178 $$origDirInfo{ImageData} = \@imageData; 2344 3179 } elsif ($offset >= 0 and $offset+$size <= $dataLen) { 2345 3180 # take data from old dir data buffer 2346 3181 $buff = substr($$dataPt, $offset, $size); 3182 } elsif ($$exifTool{TIFF_TYPE} eq 'MRW') { 3183 # TTW segment must be an even 4 bytes long, so pad now if necessary 3184 my $n = length $newData; 3185 $buff = ($n & 0x03) ? "\0" x (4 - ($n & 0x03)) : ''; 3186 $size = length($buff); 3187 # data exists after MRW TTW segment 3188 $ttwLen = length($newData) + $size unless defined $ttwLen; 3189 $newOffset = $offset + $dpos + $ttwLen - $dataLen; 2347 3190 } elsif ($raf and $raf->Seek($offset+$dbase+$dpos,0) and 2348 3191 $raf->Read($buff,$size) == $size) 2349 3192 { 2350 # data read OK 3193 # (data was read OK) 3194 # patch incorrect ThumbnailOffset in Sony A100 1.00 ARW images 3195 if ($$exifTool{TIFF_TYPE} eq 'ARW' and $$tagInfo{Name} eq 'ThumbnailOffset' and 3196 $$exifTool{Model} eq 'DSLR-A100' and $buff !~ /^\xff\xd8\xff/) 3197 { 3198 my $pos = $offset + $dbase + $dpos; 3199 my $try; 3200 if ($pos < 0x10000 and $raf->Seek($pos+0x10000,0) and 3201 $raf->Read($try,$size) == $size and $try =~ /^\xff\xd8\xff/) 3202 { 3203 $buff = $try; 3204 $exifTool->Warn('Adjusted incorrect A100 ThumbnailOffset', 1); 3205 } else { 3206 $exifTool->Error('Invalid ThumbnailImage'); 3207 } 3208 } 2351 3209 } elsif ($$tagInfo{Name} eq 'ThumbnailOffset' and $offset>=0 and $offset<$dataLen) { 2352 3210 # Grrr. The Canon 350D writes the thumbnail with an incorrect byte count … … 2372 3230 $r->Seek($tell, 0) or $exifTool->Error('Seek error'), return undef; 2373 3231 } 2374 $buff = 'LOAD' unless defined $buff; # flag indicating we must load PreviewImage 3232 # set flag if we must load PreviewImage 3233 $buff = 'LOAD_PREVIEW' unless defined $buff; 2375 3234 } else { 2376 my $dataName = $ $tagInfo{DataTag}|| $$tagInfo{Name};2377 return undef if $exifTool->Error("Error reading $dataName data in $ dirName", $inMakerNotes);3235 my $dataName = $dataTag || $$tagInfo{Name}; 3236 return undef if $exifTool->Error("Error reading $dataName data in $name", $inMakerNotes); 2378 3237 $buff = ''; 2379 3238 } 2380 if ($$tagInfo{Name} eq 'PreviewImageStart' and $exifTool->{FILE_TYPE} eq 'JPEG') { 2381 # hold onto the PreviewImage until we can determine if it fits 2382 $exifTool->{PREVIEW_INFO} or $exifTool->{PREVIEW_INFO} = { }; 2383 $exifTool->{PREVIEW_INFO}->{Data} = $buff; 2384 if ($$tagInfo{IsOffset} and $$tagInfo{IsOffset} eq '2') { 2385 $exifTool->{PREVIEW_INFO}->{NoBaseShift} = 1; 2386 } 2387 $buff = ''; 3239 if ($$tagInfo{Name} eq 'PreviewImageStart') { 3240 if ($$exifTool{FILE_TYPE} eq 'JPEG' and not $$tagInfo{MakerPreview}) { 3241 # hold onto the PreviewImage until we can determine if it fits 3242 $exifTool->{PREVIEW_INFO} or $exifTool->{PREVIEW_INFO} = { }; 3243 $exifTool->{PREVIEW_INFO}{Data} = $buff; 3244 if ($$tagInfo{IsOffset} and $$tagInfo{IsOffset} eq '2') { 3245 $exifTool->{PREVIEW_INFO}{NoBaseShift} = 1; 3246 } 3247 $buff = ''; 3248 } elsif ($$exifTool{TIFF_TYPE} eq 'ARW' and $$exifTool{Model} eq 'DSLR-A100') { 3249 # the A100 double-references the same preview, so ignore the 3250 # second one (the offset and size will be patched later) 3251 next if $$exifTool{A100PreviewLength}; 3252 $$exifTool{A100PreviewLength} = length $buff if defined $buff; 3253 } 2388 3254 } 2389 3255 # update offset accordingly and add to end of new data 2390 Set32u( length($newData)+$blockSize, \$newData, $offsetPos);3256 Set32u($newOffset, \$newData, $offsetPos); 2391 3257 # add a pointer to fix up this offset value (marked with DataTag name) 2392 $fixup->AddFixup($offsetPos, $$tagInfo{DataTag}); 3258 $fixup->AddFixup($offsetPos, $dataTag); 3259 # also add to subIfdDataFixup if necessary 3260 $subIfdDataFixup->AddFixup($offsetPos, $dataTag) if $subIfdDataFixup; 3261 # must also (sometimes) update StripOffsets in Panasonic RW2 images 3262 my $otherPos = $$offsetPair[0][5]; 3263 if ($otherPos and $$tagInfo{PanasonicHack}) { 3264 Set32u($newOffset, \$newData, $otherPos); 3265 $fixup->AddFixup($otherPos, $dataTag); 3266 } 2393 3267 if ($ifd >= 0) { 2394 $buff .= "\0" if $size & 0x01; # must be even size 3268 # buff length must be even (Note: may have changed since $size was set) 3269 $buff .= "\0" if length($buff) & 0x01; 2395 3270 $newData .= $buff; # add this strip to the data 2396 3271 } else { … … 2398 3273 } 2399 3274 } 3275 SetByteOrder($oldOrder); 2400 3276 } 2401 3277 } 3278 # verify that nothing else got written after determining TTW length 3279 if (defined $ttwLen and $ttwLen != length($newData)) { 3280 $exifTool->Error('Internal error writing MRW TTW'); 3281 } 2402 3282 } 2403 3283 # 3284 # set offsets and generate fixups for tag values which were too large for memory 3285 # 3286 $blockSize = 0; 3287 foreach $blockInfo (@imageData) { 3288 my ($pos, $size, $pad, $entry, $subFix) = @$blockInfo; 3289 if (defined $entry) { 3290 my $format = Get16u(\$newData, $entry + 2); 3291 if ($format < 1 or $format > 13) { 3292 $exifTool->Error('Internal error copying huge value'); 3293 last; 3294 } else { 3295 # set count and offset in directory entry 3296 Set32u($size / $formatSize[$format], \$newData, $entry + 4); 3297 Set32u(length($newData)+$blockSize, \$newData, $entry + 8); 3298 $fixup->AddFixup($entry + 8); 3299 # create special fixup for SubIFD data 3300 if ($imageDataFlag eq 'SubIFD') { 3301 my $subIfdDataFixup = new Image::ExifTool::Fixup; 3302 $subIfdDataFixup->AddFixup($entry + 8); 3303 # save fixup in imageData list 3304 $$blockInfo[4] = $subIfdDataFixup; 3305 } 3306 # must reset entry pointer so we don't use it again in a parent IFD! 3307 $$blockInfo[3] = undef; 3308 } 3309 } 3310 # apply additional shift required for contained SubIFD image data offsets 3311 if ($subFix and defined $$subFix{BlockLen} and $numBlocks > 0) { 3312 # our offset expects the data at the end of the SubIFD block (BlockLen + Start), 3313 # but it will actually be at length($newData) + $blockSize. So adjust 3314 # accordingly (and subtract an extra Start because this shift is applied later) 3315 $subFix->{Shift} += length($newData) - $$subFix{BlockLen} - 2 * $$subFix{Start} + $blockSize; 3316 $subFix->ApplyFixup(\$newData); 3317 } 3318 $blockSize += $size + $pad; 3319 --$numBlocks; 3320 } 3321 # 2404 3322 # apply final shift to new data position if this is the top level IFD 2405 3323 # 2406 3324 unless ($$dirInfo{Fixup}) { 2407 my $newDataPos = $$dirInfo{NewDataPos} || 0; 3325 my $hdrPtr = $$dirInfo{HeaderPtr}; 3326 my $newDataPos = $hdrPtr ? length $$hdrPtr : $$dirInfo{NewDataPos} || 0; 2408 3327 # adjust CanonVRD offset to point to end of regular TIFF if necessary 2409 3328 # (NOTE: This will be incorrect if multiple trailers exist, 2410 # but it is unlikely that it could ever be correct in this case anyway) 3329 # but it is unlikely that it could ever be correct in this case anyway. 3330 # Also, this doesn't work for JPEG images (but CanonDPP doesn't set 3331 # this when editing JPEG images anyway)) 2411 3332 $fixup->SetMarkerPointers(\$newData, 'CanonVRD', length($newData) + $blockSize); 2412 3333 if ($newDataPos) { … … 2414 3335 $fixup->ApplyFixup(\$newData); 2415 3336 } 3337 # save fixup for adjusting Leica trailer offset if necessary 3338 if ($$exifTool{LeicaTrailer}) { 3339 my $trail = $$exifTool{LeicaTrailer}; 3340 $$trail{Fixup} or $$trail{Fixup} = new Image::ExifTool::Fixup; 3341 $$trail{Fixup}->AddFixup($fixup); 3342 } 2416 3343 # save fixup for PreviewImage in JPEG file if necessary 2417 3344 my $previewInfo = $exifTool->{PREVIEW_INFO}; 2418 3345 if ($previewInfo) { 2419 my $pt = \$previewInfo->{Data}; # image data or 'LOAD ' flag3346 my $pt = \$previewInfo->{Data}; # image data or 'LOAD_PREVIEW' flag 2420 3347 # now that we know the size of the EXIF data, first test to see if our new image fits 2421 3348 # inside the EXIF segment (remember about the TIFF and EXIF headers: 8+6 bytes) 2422 if (($$pt ne 'LOAD' and length($$pt) + length($newData) + 14 <= 0xfffd) or 3349 if (($$pt ne 'LOAD_PREVIEW' and length($$pt) + length($newData) + 14 <= 0xfffd and 3350 not $previewInfo->{IsTrailer}) or 2423 3351 $previewInfo->{IsShort}) # must fit in this segment if using short pointers 2424 3352 { 2425 3353 # It fits! (or must exist in EXIF segment), so fixup the 2426 3354 # PreviewImage pointers and stuff the preview image in here 2427 my $newPos = length($newData) + ($newDataPos || 0);3355 my $newPos = length($newData) + $newDataPos; 2428 3356 $newPos += ($previewInfo->{BaseShift} || 0); 2429 3357 if ($previewInfo->{Relative}) { … … 2441 3369 $previewInfo->{Fixup}->AddFixup($fixup); 2442 3370 } 2443 } else { 2444 # delete both IFD0 and IFD1 if only mandatory tags remain 2445 $newData = '' if defined $newData and $deleteAll; 3371 } elsif (defined $newData and $deleteAll) { 3372 $newData = ''; # delete both IFD0 and IFD1 since only mandatory tags remain 3373 } elsif ($$exifTool{A100PreviewLength}) { 3374 # save preview image start for patching A100 quirks later 3375 $$exifTool{A100PreviewStart} = $fixup->GetMarkerPointers(\$newData, 'PreviewImage'); 2446 3376 } 2447 3377 # save location of last IFD for use in Canon RAW header 2448 3378 if ($newDataPos == 16) { 2449 3379 my @ifdPos = $fixup->GetMarkerPointers(\$newData,'NextIFD'); 2450 $_[1]->{LastIFD} = pop @ifdPos; 3380 $$origDirInfo{LastIFD} = pop @ifdPos; 3381 } 3382 # recrypt SR2 SubIFD data if necessary 3383 my $key = $$exifTool{SR2SubIFDKey}; 3384 if ($key) { 3385 my $start = $fixup->GetMarkerPointers(\$newData, 'SR2SubIFDOffset'); 3386 my $len = $$exifTool{SR2SubIFDLength}; 3387 # (must subtract 8 for size of TIFF header) 3388 if ($start and $start - 8 + $len <= length $newData) { 3389 require Image::ExifTool::Sony; 3390 Image::ExifTool::Sony::Decrypt(\$newData, $start - 8, $len, $key); 3391 } 2451 3392 } 2452 3393 } … … 2476 3417 =head1 AUTHOR 2477 3418 2478 Copyright 2003-20 07, Phil Harvey (phil at owl.phy.queensu.ca)3419 Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca) 2479 3420 2480 3421 This library is free software; you can redistribute it and/or modify it
Note:
See TracChangeset
for help on using the changeset viewer.