exiftool_vendored 12.63.0 → 12.64.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/Changes +22 -1
- data/bin/MANIFEST +3 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +47 -46
- data/bin/config_files/guano.config +161 -0
- data/bin/exiftool +73 -53
- data/bin/lib/Image/ExifTool/Apple.pm +6 -3
- data/bin/lib/Image/ExifTool/CanonVRD.pm +4 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +4 -3
- data/bin/lib/Image/ExifTool/Lang/fr.pm +1467 -202
- data/bin/lib/Image/ExifTool/Matroska.pm +16 -1
- data/bin/lib/Image/ExifTool/Nikon.pm +419 -5
- data/bin/lib/Image/ExifTool/NikonCustom.pm +13 -3
- data/bin/lib/Image/ExifTool/PDF.pm +9 -1
- data/bin/lib/Image/ExifTool/PLIST.pm +8 -1
- data/bin/lib/Image/ExifTool/QuickTime.pm +33 -9
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +2 -1
- data/bin/lib/Image/ExifTool/README +1 -1
- data/bin/lib/Image/ExifTool/Sony.pm +1 -0
- data/bin/lib/Image/ExifTool/TagLookup.pm +4719 -4640
- data/bin/lib/Image/ExifTool/TagNames.pod +175 -1
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +21 -9
- data/bin/lib/Image/ExifTool/WriteXMP.pl +2 -2
- data/bin/lib/Image/ExifTool/Writer.pl +21 -4
- data/bin/lib/Image/ExifTool/XMPStruct.pl +96 -28
- data/bin/lib/Image/ExifTool.pm +17 -10
- data/bin/lib/Image/ExifTool.pod +71 -51
- data/bin/perl-Image-ExifTool.spec +44 -44
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +7 -6
@@ -12,7 +12,7 @@ meta information extracted from or written to a file.
|
|
12
12
|
=head1 TAG TABLES
|
13
13
|
|
14
14
|
The tables listed below give the names of all tags recognized by ExifTool.
|
15
|
-
They contain a total of
|
15
|
+
They contain a total of 26591 tags, with 16966 unique tag names.
|
16
16
|
|
17
17
|
B<Tag ID>, B<Index#> or B<Sequence> is given in the first column of each
|
18
18
|
table. A B<Tag ID> is the computer-readable equivalent of a tag name, and
|
@@ -7199,6 +7199,7 @@ Tags extracted from the maker notes of iPhone images.
|
|
7199
7199
|
0x0025 SceneFlags? int32s
|
7200
7200
|
0x0026 SignalToNoiseRatioType? int32s
|
7201
7201
|
0x0027 SignalToNoiseRatio rational64s
|
7202
|
+
0x002b PhotoIdentifier string
|
7202
7203
|
0x002f FocusPosition int32s
|
7203
7204
|
0x0030 HDRGain rational64s
|
7204
7205
|
0x0038 AFMeasuredDepth int32s
|
@@ -14715,6 +14716,7 @@ These tags are extracted from encrypted data in images from the Z9.
|
|
14715
14716
|
4 FirmwareVersion no
|
14716
14717
|
48 SequenceOffset Nikon SeqInfoZ9
|
14717
14718
|
88 Offset13 Nikon Offset13InfoZ9
|
14719
|
+
128 AutoCaptureOffset Nikon AutoCaptureInfo
|
14718
14720
|
132 OrientOffset Nikon OrientationInfo
|
14719
14721
|
140 MenuOffset Nikon MenuInfoZ9
|
14720
14722
|
|
@@ -14734,6 +14736,21 @@ These tags are extracted from encrypted data in images from the Z9.
|
|
14734
14736
|
3050 AFAreaInitialWidth no
|
14735
14737
|
3051 AFAreaInitialHeight no
|
14736
14738
|
|
14739
|
+
=head3 Nikon AutoCaptureInfo Tags
|
14740
|
+
|
14741
|
+
Index1 Tag Name Writable
|
14742
|
+
------ -------- --------
|
14743
|
+
1 AutoCaptureCriteria int8u~
|
14744
|
+
55 AutoCaptureRecordingTime int8u
|
14745
|
+
56 AutoCaptureWaitTime int8u
|
14746
|
+
74 AutoCaptureDistanceFar int8u~
|
14747
|
+
78 AutoCaptureDistanceNear int8u~
|
14748
|
+
95 AutoCaptureCriteriaMotionDirection int8u~
|
14749
|
+
99 AutoCaptureCriteriaMotionSpeed int8u
|
14750
|
+
100 AutoCaptureCriteriaMotionSize int8u
|
14751
|
+
105 AutoCaptureCriteriaSubjectSize int8u
|
14752
|
+
106 AutoCaptureCriteriaSubjectType int8u
|
14753
|
+
|
14737
14754
|
=head3 Nikon MenuInfoZ9 Tags
|
14738
14755
|
|
14739
14756
|
Index1 Tag Name Writable
|
@@ -14741,6 +14758,8 @@ These tags are extracted from encrypted data in images from the Z9.
|
|
14741
14758
|
16 MenuSettingsOffsetZ9 Nikon MenuSettingsZ9
|
14742
14759
|
MenuSettingsOffsetZ9v3 -
|
14743
14760
|
Nikon MenuSettingsZ9v3
|
14761
|
+
-
|
14762
|
+
Nikon MenuSettingsZ9v4
|
14744
14763
|
|
14745
14764
|
=head3 Nikon MenuSettingsZ9 Tags
|
14746
14765
|
|
@@ -14900,6 +14919,144 @@ These tags are used by the Z9 firmware 3.00.
|
|
14900
14919
|
1810 PreReleaseBurstLength int8u
|
14901
14920
|
1812 PostReleaseBurstLength int8u
|
14902
14921
|
|
14922
|
+
=head3 Nikon MenuSettingsZ9v4 Tags
|
14923
|
+
|
14924
|
+
These tags are used by the Z9 firmware 3.00.
|
14925
|
+
|
14926
|
+
Index1 Tag Name Writable
|
14927
|
+
--------------- --------
|
14928
|
+
72 HighFrameRate int8u
|
14929
|
+
154 MultipleExposureMode int8u
|
14930
|
+
156 MultiExposureShots int8u
|
14931
|
+
204 Intervals int32u
|
14932
|
+
208 ShotsPerInterval int32u
|
14933
|
+
248 FocusShiftNumberShots int8u
|
14934
|
+
252 FocusShiftStepWidth int8u
|
14935
|
+
256 FocusShiftInterval int8u~
|
14936
|
+
260 FocusShiftExposureLock? int8u
|
14937
|
+
290 PhotoShootingMenuBank int8u
|
14938
|
+
292 ExtendedMenuBanks int8u
|
14939
|
+
328 PhotoShootingMenuBankImageArea int8u
|
14940
|
+
342 AutoISO int8u
|
14941
|
+
344 ISOAutoHiLimit? int16u
|
14942
|
+
346 ISOAutoFlashLimit? int16u
|
14943
|
+
354 ISOAutoShutterTime no
|
14944
|
+
436 MovieVignetteControl? int8u
|
14945
|
+
438 DiffractionCompensation int8u
|
14946
|
+
440 FlickerReductionShooting int8u
|
14947
|
+
444 FlashControlMode int8u
|
14948
|
+
446 FlashMasterCompensation? int8s
|
14949
|
+
450 FlashGNDistance? no
|
14950
|
+
454 FlashOutput? int8u
|
14951
|
+
548 AFAreaMode int8u
|
14952
|
+
550 VRMode int8u
|
14953
|
+
554 BracketSet int8u
|
14954
|
+
556 BracketProgram int8u
|
14955
|
+
558 BracketIncrement int8u
|
14956
|
+
576 SecondarySlotFunction int8u
|
14957
|
+
586 Slot2JpgSize? int8u
|
14958
|
+
592 DXCropAlert int8u
|
14959
|
+
594 SubjectDetection int8u
|
14960
|
+
596 DynamicAFAreaSize int8u
|
14961
|
+
636 HighFrequencyFlickerReductionShooting? int8u
|
14962
|
+
646 MovieImageArea? int8u & 0x01
|
14963
|
+
656 MovieType? int8u
|
14964
|
+
658 MovieISOAutoHiLimit? int16u
|
14965
|
+
660 MovieISOAutoControlManualMode? int8u
|
14966
|
+
662 MovieISOAutoManualMode? int16u
|
14967
|
+
736 MovieActiveD-Lighting? int8u
|
14968
|
+
738 MovieHighISONoiseReduction? int8u
|
14969
|
+
744 MovieFlickerReduction int8u
|
14970
|
+
746 MovieMeteringMode? int8u
|
14971
|
+
748 MovieFocusMode? int8u
|
14972
|
+
750 MovieAFAreaMode int8u
|
14973
|
+
752 MovieVRMode? int8u
|
14974
|
+
756 MovieElectronicVR? int8u
|
14975
|
+
758 MovieSoundRecording? int8u
|
14976
|
+
760 MicrophoneSensitivity? int8u
|
14977
|
+
762 MicrophoneAttenuator? int8u
|
14978
|
+
764 MicrophoneFrequencyResponse? int8u
|
14979
|
+
766 WindNoiseReduction? int8u
|
14980
|
+
788 MovieToneMap? int8u
|
14981
|
+
794 MovieFrameSize? int8u
|
14982
|
+
796 MovieFrameRate? int8u
|
14983
|
+
802 MicrophoneJackPower? int8u
|
14984
|
+
803 MovieDXCropAlert? int8u
|
14985
|
+
804 MovieSubjectDetection? int8u
|
14986
|
+
812 MovieHighResZoom? int8u
|
14987
|
+
847 CustomSettingsZ9 NikonCustom SettingsZ9
|
14988
|
+
1474 Language? int8u
|
14989
|
+
1476 TimeZone int8u
|
14990
|
+
1482 MonitorBrightness? int8u
|
14991
|
+
1504 AFFineTune? int8u
|
14992
|
+
1532 NonCPULens1FocalLength? int16s~
|
14993
|
+
1536 NonCPULens2FocalLength? int16s~
|
14994
|
+
1540 NonCPULens3FocalLength? int16s~
|
14995
|
+
1544 NonCPULens4FocalLength? int16s~
|
14996
|
+
1548 NonCPULens5FocalLength? int16s~
|
14997
|
+
1552 NonCPULens6FocalLength? int16s~
|
14998
|
+
1556 NonCPULens7FocalLength? int16s~
|
14999
|
+
1560 NonCPULens8FocalLength? int16s~
|
15000
|
+
1564 NonCPULens9FocalLength? int16s~
|
15001
|
+
1568 NonCPULens10FocalLength? int16s~
|
15002
|
+
1572 NonCPULens11FocalLength? int16s~
|
15003
|
+
1576 NonCPULens21FocalLength? int16s~
|
15004
|
+
1580 NonCPULens13FocalLength? int16s~
|
15005
|
+
1584 NonCPULens14FocalLength? int16s~
|
15006
|
+
1588 NonCPULens15FocalLength? int16s~
|
15007
|
+
1592 NonCPULens16FocalLength? int16s~
|
15008
|
+
1596 NonCPULens17FocalLength? int16s~
|
15009
|
+
1600 NonCPULens18FocalLength? int16s~
|
15010
|
+
1604 NonCPULens19FocalLength? int16s~
|
15011
|
+
1608 NonCPULens20FocalLength? int16s~
|
15012
|
+
1612 NonCPULens1MaxAperture? int16s~
|
15013
|
+
1616 NonCPULens2MaxAperture? int16s~
|
15014
|
+
1620 NonCPULens3MaxAperture? int16s~
|
15015
|
+
1624 NonCPULens4MaxAperture? int16s~
|
15016
|
+
1628 NonCPULens5MaxAperture? int16s~
|
15017
|
+
1632 NonCPULens6MaxAperture? int16s~
|
15018
|
+
1636 NonCPULens7MaxAperture? int16s~
|
15019
|
+
1640 NonCPULens8MaxAperture? int16s~
|
15020
|
+
1644 NonCPULens9MaxAperture? int16s~
|
15021
|
+
1648 NonCPULens10MaxAperture? int16s~
|
15022
|
+
1652 NonCPULens11MaxAperture? int16s~
|
15023
|
+
1656 NonCPULens12MaxAperture? int16s~
|
15024
|
+
1660 NonCPULens13MaxAperture? int16s~
|
15025
|
+
1664 NonCPULens14MaxAperture? int16s~
|
15026
|
+
1668 NonCPULens15MaxAperture? int16s~
|
15027
|
+
1672 NonCPULens16MaxAperture? int16s~
|
15028
|
+
1676 NonCPULens17MaxAperture? int16s~
|
15029
|
+
1680 NonCPULens18MaxAperture? int16s~
|
15030
|
+
1684 NonCPULens19MaxAperture? int16s~
|
15031
|
+
1688 NonCPULens20MaxAperture? int16s~
|
15032
|
+
1704 HDMIOutputResolution int8u
|
15033
|
+
1717 SetClockFromLocationData? int8u
|
15034
|
+
1724 AirplaneMode? int8u
|
15035
|
+
1725 EmptySlotRelease? int8u
|
15036
|
+
1760 EnergySavingMode? int8u
|
15037
|
+
1784 RecordLocationData? int8u
|
15038
|
+
1788 USBPowerDelivery? int8u
|
15039
|
+
1797 SensorShield? int8u
|
15040
|
+
1862 AutoCapturePreset int8u
|
15041
|
+
1864 FocusShiftAutoReset? int8u
|
15042
|
+
1922 PreReleaseBurstLength int8u
|
15043
|
+
1924 PostReleaseBurstLength int8u
|
15044
|
+
1938 VerticalISOButton int8u
|
15045
|
+
1940 ExposureCompensationButton int8u
|
15046
|
+
1942 ISOButton int8u
|
15047
|
+
2002 ViewModeShowEffectsOfSettings? int8u
|
15048
|
+
2004 DispButton int8u
|
15049
|
+
2048 ExposureDelay fixed32u~
|
15050
|
+
2056 PlaybackButton int8u
|
15051
|
+
2058 WBButton int8u
|
15052
|
+
2060 BracketButton int8u
|
15053
|
+
2062 FlashModeButton int8u
|
15054
|
+
2064 LensFunc1ButtonPlaybackMode int8u
|
15055
|
+
2066 LensFunc2ButtonPlaybackMode int8u
|
15056
|
+
2068 PlaybackButtonPlaybackMode int8u
|
15057
|
+
2070 BracketButtonPlaybackMode int8u
|
15058
|
+
2072 FlashModeButtonPlaybackMode int8u
|
15059
|
+
|
14903
15060
|
=head3 Nikon ShotInfo Tags
|
14904
15061
|
|
14905
15062
|
This information is encrypted for ShotInfoVersion 02xx, and some tags are
|
@@ -28914,12 +29071,27 @@ atoms.
|
|
28914
29071
|
24 AudioChannels no
|
28915
29072
|
26 AudioBitsPerSample no
|
28916
29073
|
32 AudioSampleRate no
|
29074
|
+
'SA3D' SpatialAudio QuickTime SpatialAudio
|
28917
29075
|
'chan' AudioChannelLayout QuickTime ChannelLayout
|
28918
29076
|
'damr' DecodeConfig QuickTime DecodeConfig
|
28919
29077
|
'pinf' PurchaseInfo QuickTime ProtectionInfo
|
28920
29078
|
'sinf' ProtectionInfo QuickTime ProtectionInfo
|
28921
29079
|
'wave' Wave QuickTime Wave
|
28922
29080
|
|
29081
|
+
=head3 QuickTime SpatialAudio Tags
|
29082
|
+
|
29083
|
+
Spatial Audio tags.
|
29084
|
+
|
29085
|
+
Index1 Tag Name Writable
|
29086
|
+
------ -------- --------
|
29087
|
+
0 SpatialAudioVersion no
|
29088
|
+
1 AmbisonicType no
|
29089
|
+
2 AmbisonicOrder no
|
29090
|
+
6 AmbisonicChannelOrdering no
|
29091
|
+
7 AmbisonicNormalization no
|
29092
|
+
8 AmbisonicChannels no
|
29093
|
+
12 AmbisonicChannelMap no
|
29094
|
+
|
28923
29095
|
=head3 QuickTime ChannelLayout Tags
|
28924
29096
|
|
28925
29097
|
Audio channel layout.
|
@@ -31198,6 +31370,7 @@ L<https://www.matroska.org/technical/tagging.html>).
|
|
31198
31370
|
'SCREENPLAY_BY' ScreenplayBy no
|
31199
31371
|
'SORT_WITH' SortWith no
|
31200
31372
|
'SOUND_ENGINEER' SoundEngineer no
|
31373
|
+
'SPHERICAL-VIDEO' SphericalVideoXML XMP
|
31201
31374
|
'SUBJECT' Subject no
|
31202
31375
|
'SUBTITLE' Subtitle no
|
31203
31376
|
'SUMMARY' Summary no
|
@@ -31211,6 +31384,7 @@ L<https://www.matroska.org/technical/tagging.html>).
|
|
31211
31384
|
'TVDB' TVDB no
|
31212
31385
|
'URL' URL no
|
31213
31386
|
'WRITTEN_BY' WrittenBy no
|
31387
|
+
'spherical-video' SphericalVideoXML XMP
|
31214
31388
|
|
31215
31389
|
=head2 MOI Tags
|
31216
31390
|
|
@@ -973,16 +973,14 @@ sub WriteQuickTime($$$)
|
|
973
973
|
}
|
974
974
|
} elsif ($tag eq 'CTBO' or $tag eq 'uuid') { # hack for updating CR3 CTBO offsets
|
975
975
|
push @{$$dirInfo{ChunkOffset}}, [ $tag, length($$outfile), length($hdr) + $size ];
|
976
|
-
} elsif (not $flg) {
|
977
|
-
|
978
|
-
$
|
979
|
-
|
976
|
+
} elsif (not $flg or $flg == 1) {
|
977
|
+
# assume "1" if stsd is yet to be read
|
978
|
+
$flg or $$et{AssumedDataRef} = 1;
|
979
|
+
# must update offsets since the data is in this file
|
980
|
+
push @{$$dirInfo{ChunkOffset}}, [ $tag, length($$outfile) + length($hdr), $size ];
|
980
981
|
} elsif ($flg == 3) {
|
981
982
|
$et->Error("Can't write files with mixed internal/external media data");
|
982
983
|
return $rtnVal;
|
983
|
-
} elsif ($flg == 1) {
|
984
|
-
# must update offsets since the data is in this file
|
985
|
-
push @{$$dirInfo{ChunkOffset}}, [ $tag, length($$outfile) + length($hdr), $size ];
|
986
984
|
}
|
987
985
|
}
|
988
986
|
|
@@ -1036,8 +1034,10 @@ sub WriteQuickTime($$$)
|
|
1036
1034
|
|
1037
1035
|
if ($subdir) { # process atoms in this container from a buffer in memory
|
1038
1036
|
|
1039
|
-
|
1040
|
-
|
1037
|
+
if ($tag eq 'trak') {
|
1038
|
+
undef $$et{HandlerType}; # init handler type for this track
|
1039
|
+
delete $$et{AssumedDataRef};
|
1040
|
+
}
|
1041
1041
|
my $subName = $$subdir{DirName} || $$tagInfo{Name};
|
1042
1042
|
my $start = $$subdir{Start} || 0;
|
1043
1043
|
my $base = ($$dirInfo{Base} || 0) + $raf->Tell() - $size;
|
@@ -1103,6 +1103,11 @@ sub WriteQuickTime($$$)
|
|
1103
1103
|
$$et{CHANGED} = $oldChanged;
|
1104
1104
|
undef $newData;
|
1105
1105
|
}
|
1106
|
+
if ($tag eq 'trak' and $$et{AssumedDataRef}) {
|
1107
|
+
my $grp = $$et{CUR_WRITE_GROUP} || $dirName;
|
1108
|
+
$et->Error("Can't locate data reference to update offsets for $grp");
|
1109
|
+
delete $$et{AssumedDataRef};
|
1110
|
+
}
|
1106
1111
|
$$et{CUR_WRITE_GROUP} = $oldWriteGroup;
|
1107
1112
|
SetByteOrder('MM');
|
1108
1113
|
# add back header if necessary
|
@@ -1405,6 +1410,13 @@ sub WriteQuickTime($$$)
|
|
1405
1410
|
$flg = 1; # (this seems to be the case)
|
1406
1411
|
}
|
1407
1412
|
$$et{QtDataFlg} = $flg;
|
1413
|
+
if ($$et{AssumedDataRef}) {
|
1414
|
+
if ($flg != $$et{AssumedDataRef}) {
|
1415
|
+
my $grp = $$et{CUR_WRITE_GROUP} || $parent;
|
1416
|
+
$et->Error("Assumed incorrect data reference for $grp (was $flg)");
|
1417
|
+
}
|
1418
|
+
delete $$et{AssumedDataRef};
|
1419
|
+
}
|
1408
1420
|
}
|
1409
1421
|
if ($tagInfo and $$tagInfo{WriteLast}) {
|
1410
1422
|
$writeLast = ($writeLast || '') . $hdr . $buff;
|
@@ -176,7 +176,7 @@ sub CheckXMP($$$;$)
|
|
176
176
|
require 'Image/ExifTool/XMPStruct.pl';
|
177
177
|
my ($item, $err, $w, $warn);
|
178
178
|
unless (ref $$valPtr) {
|
179
|
-
($$valPtr, $warn) = InflateStruct($valPtr);
|
179
|
+
($$valPtr, $warn) = InflateStruct($et, $valPtr);
|
180
180
|
# expect a structure HASH ref or ARRAY of structures
|
181
181
|
unless (ref $$valPtr) {
|
182
182
|
$$valPtr eq '' and $$valPtr = { }, return undef; # allow empty structures
|
@@ -189,7 +189,7 @@ sub CheckXMP($$$;$)
|
|
189
189
|
$$valPtr = \@copy; # return the copy
|
190
190
|
foreach $item (@copy) {
|
191
191
|
unless (ref $item eq 'HASH') {
|
192
|
-
($item, $w) = InflateStruct(\$item); # deserialize structure
|
192
|
+
($item, $w) = InflateStruct($et, \$item); # deserialize structure
|
193
193
|
$w and $warn = $w;
|
194
194
|
next if ref $item eq 'HASH';
|
195
195
|
$err = 'Improperly formed structure';
|
@@ -139,7 +139,7 @@ my @delGroups = qw(
|
|
139
139
|
Adobe AFCP APP0 APP1 APP2 APP3 APP4 APP5 APP6 APP7 APP8 APP9 APP10 APP11
|
140
140
|
APP12 APP13 APP14 APP15 CanonVRD CIFF Ducky EXIF ExifIFD File FlashPix
|
141
141
|
FotoStation GlobParamIFD GPS ICC_Profile IFD0 IFD1 Insta360 InteropIFD IPTC
|
142
|
-
ItemList JFIF Jpeg2000 Keys MakerNotes Meta MetaIFD Microsoft MIE MPF
|
142
|
+
ItemList JFIF Jpeg2000 JUMBF Keys MakerNotes Meta MetaIFD Microsoft MIE MPF
|
143
143
|
NikonApp NikonCapture PDF PDF-update PhotoMechanic Photoshop PNG PNG-pHYs
|
144
144
|
PrintIM QuickTime RMETA RSRC SubIFD Trailer UserData XML XML-* XMP XMP-*
|
145
145
|
);
|
@@ -1028,7 +1028,7 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
1028
1028
|
foreach (@vals) {
|
1029
1029
|
if (ref $_ eq 'HASH') {
|
1030
1030
|
require 'Image/ExifTool/XMPStruct.pl';
|
1031
|
-
$_ = Image::ExifTool::XMP::SerializeStruct($_);
|
1031
|
+
$_ = Image::ExifTool::XMP::SerializeStruct($self, $_);
|
1032
1032
|
}
|
1033
1033
|
print $out "$$self{INDENT2}$verb $wgrp1:$tag$fromList if value is '${_}'\n";
|
1034
1034
|
}
|
@@ -1314,6 +1314,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1314
1314
|
ScanForXMP => $$options{ScanForXMP},
|
1315
1315
|
StrictDate => defined $$options{StrictDate} ? $$options{StrictDate} : 1,
|
1316
1316
|
Struct => $structOpt,
|
1317
|
+
StructFormat => $$options{StructFormat},
|
1317
1318
|
SystemTags => $$options{SystemTags},
|
1318
1319
|
TimeZone => $$options{TimeZone},
|
1319
1320
|
Unknown => $$options{Unknown},
|
@@ -1764,7 +1765,14 @@ GNV_TagInfo: foreach $tagInfo (@tagInfoList) {
|
|
1764
1765
|
}
|
1765
1766
|
}
|
1766
1767
|
# return our value(s)
|
1767
|
-
|
1768
|
+
if (wantarray) {
|
1769
|
+
# remove duplicates if requested
|
1770
|
+
if (@$vals > 1 and $self->Options('NoDups')) {
|
1771
|
+
my %seen;
|
1772
|
+
@$vals = grep { !$seen{$_}++ } @$vals;
|
1773
|
+
}
|
1774
|
+
return @$vals;
|
1775
|
+
}
|
1768
1776
|
return $$vals[0];
|
1769
1777
|
}
|
1770
1778
|
|
@@ -3284,7 +3292,7 @@ sub InsertTagValues($$$;$$$)
|
|
3284
3292
|
}
|
3285
3293
|
} elsif (ref $val eq 'HASH') {
|
3286
3294
|
require 'Image/ExifTool/XMPStruct.pl';
|
3287
|
-
$val = Image::ExifTool::XMP::SerializeStruct($val);
|
3295
|
+
$val = Image::ExifTool::XMP::SerializeStruct($self, $val);
|
3288
3296
|
} elsif (not defined $val) {
|
3289
3297
|
$val = $$self{OPTIONS}{MissingTagValue} if $asList;
|
3290
3298
|
}
|
@@ -3768,6 +3776,8 @@ sub GetNewValueHash($$;$$$$)
|
|
3768
3776
|
# this is a bit tricky: we want to add to a protected nvHash only if we
|
3769
3777
|
# are adding a conditional delete ($_[5] true or DelValue with no Shift)
|
3770
3778
|
# or accumulating List items (NoReplace true)
|
3779
|
+
# (NOTE: this should be looked into --> lists may be accumulated instead of being replaced
|
3780
|
+
# as expected when copying to the same list from different dynamic -tagsFromFile source files)
|
3771
3781
|
if ($protect and not ($opts{create} and ($$nvHash{NoReplace} or $_[5] or
|
3772
3782
|
($$nvHash{DelValue} and not defined $$nvHash{Shift}))))
|
3773
3783
|
{
|
@@ -5599,6 +5609,8 @@ sub WriteJPEG($$)
|
|
5599
5609
|
$s =~ /^(Meta|META|Exif)\0\0/ and $dirName = 'Meta';
|
5600
5610
|
} elsif ($marker == 0xe5) {
|
5601
5611
|
$s =~ /^RMETA\0/ and $dirName = 'RMETA';
|
5612
|
+
} elsif ($marker == 0xeb) {
|
5613
|
+
$s =~ /^JP/ and $dirName = 'JUMBF';
|
5602
5614
|
} elsif ($marker == 0xec) {
|
5603
5615
|
$s =~ /^Ducky/ and $dirName = 'Ducky';
|
5604
5616
|
} elsif ($marker == 0xed) {
|
@@ -6464,6 +6476,11 @@ sub WriteJPEG($$)
|
|
6464
6476
|
$segType = 'Ricoh RMETA';
|
6465
6477
|
$$delGroup{RMETA} and $del = 1;
|
6466
6478
|
}
|
6479
|
+
} elsif ($marker == 0xeb) { # APP10 (JUMBF)
|
6480
|
+
if ($$segDataPt =~ /^JP/) {
|
6481
|
+
$segType = 'JUMBF';
|
6482
|
+
$$delGroup{JUMBF} and $del = 1;
|
6483
|
+
}
|
6467
6484
|
} elsif ($marker == 0xec) { # APP12 (Ducky)
|
6468
6485
|
if ($$segDataPt =~ /^Ducky/) {
|
6469
6486
|
$segType = 'Ducky';
|
@@ -14,42 +14,55 @@ use vars qw(%specialStruct %stdXlatNS);
|
|
14
14
|
use Image::ExifTool qw(:Utils);
|
15
15
|
use Image::ExifTool::XMP;
|
16
16
|
|
17
|
-
sub SerializeStruct(
|
18
|
-
sub InflateStruct(
|
17
|
+
sub SerializeStruct($$;$);
|
18
|
+
sub InflateStruct($$;$);
|
19
19
|
sub DumpStruct($;$);
|
20
20
|
sub CheckStruct($$$);
|
21
21
|
sub AddNewStruct($$$$$$);
|
22
22
|
sub ConvertStruct($$$$;$);
|
23
|
+
sub EscapeJSON($;$);
|
24
|
+
|
25
|
+
# lookups for JSON characters that we escape specially
|
26
|
+
my %jsonChar = ( '"'=>'"', '\\'=>'\\', "\b"=>'b', "\f"=>'f', "\n"=>'n', "\r"=>'r', "\t"=>'t' );
|
27
|
+
my %jsonEsc = ( '"'=>'"', '\\'=>'\\', 'b'=>"\b", 'f'=>"\f", 'n'=>"\n", 'r'=>"\r", 't'=>"\t" );
|
23
28
|
|
24
29
|
#------------------------------------------------------------------------------
|
25
30
|
# Serialize a structure (or other object) into a simple string
|
26
|
-
# Inputs: 0) HASH ref, ARRAY ref, or SCALAR,
|
27
|
-
# Returns: serialized structure string
|
31
|
+
# Inputs: 0) ExifTool ref, 1) HASH ref, ARRAY ref, or SCALAR, 2) closing bracket (or undef)
|
32
|
+
# Returns: serialized structure string (in format specified by StructFormat option)
|
28
33
|
# eg) "{field=text with {braces|}|, and a comma, field2=val2,field3={field4=[a,b]}}"
|
29
|
-
sub SerializeStruct(
|
34
|
+
sub SerializeStruct($$;$)
|
30
35
|
{
|
31
|
-
my ($obj, $ket) = @_;
|
36
|
+
my ($et, $obj, $ket) = @_;
|
32
37
|
my ($key, $val, @vals, $rtnVal);
|
38
|
+
my $sfmt = $et->Options('StructFormat');
|
33
39
|
|
34
40
|
if (ref $obj eq 'HASH') {
|
35
41
|
# support hashes with ordered keys
|
36
42
|
my @keys = $$obj{_ordered_keys_} ? @{$$obj{_ordered_keys_}} : sort keys %$obj;
|
37
43
|
foreach $key (@keys) {
|
38
|
-
|
44
|
+
my $hdr = $sfmt ? EscapeJSON($key) . ':' : $key . '=';
|
45
|
+
push @vals, $hdr . SerializeStruct($et, $$obj{$key}, '}');
|
39
46
|
}
|
40
47
|
$rtnVal = '{' . join(',', @vals) . '}';
|
41
48
|
} elsif (ref $obj eq 'ARRAY') {
|
42
49
|
foreach $val (@$obj) {
|
43
|
-
push @vals, SerializeStruct($val, ']');
|
50
|
+
push @vals, SerializeStruct($et, $val, ']');
|
44
51
|
}
|
45
52
|
$rtnVal = '[' . join(',', @vals) . ']';
|
46
53
|
} elsif (defined $obj) {
|
47
54
|
$obj = $$obj if ref $obj eq 'SCALAR';
|
48
55
|
# escape necessary characters in string (closing bracket plus "," and "|")
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
56
|
+
if ($sfmt) {
|
57
|
+
$rtnVal = EscapeJSON($obj, $sfmt eq 'JSONQ');
|
58
|
+
} else {
|
59
|
+
my $pat = $ket ? "\\$ket|,|\\|" : ',|\\|';
|
60
|
+
($rtnVal = $obj) =~ s/($pat)/|$1/g;
|
61
|
+
# also must escape opening bracket or whitespace at start of string
|
62
|
+
$rtnVal =~ s/^([\s\[\{])/|$1/;
|
63
|
+
}
|
64
|
+
} elsif ($sfmt) {
|
65
|
+
$rtnVal = 'null';
|
53
66
|
} else {
|
54
67
|
$rtnVal = ''; # allow undefined list items
|
55
68
|
}
|
@@ -58,21 +71,25 @@ sub SerializeStruct($;$)
|
|
58
71
|
|
59
72
|
#------------------------------------------------------------------------------
|
60
73
|
# Inflate structure (or other object) from a serialized string
|
61
|
-
# Inputs: 0) reference to object in string form
|
62
|
-
#
|
74
|
+
# Inputs: 0) ExifTool ref, 1) reference to object in string form
|
75
|
+
# (serialized using the '|' escape, or JSON)
|
76
|
+
# 2) extra delimiter for scalar values delimiters
|
63
77
|
# Returns: 0) object as a SCALAR, HASH ref, or ARRAY ref (or undef on error),
|
64
78
|
# 1) warning string (or undef)
|
65
79
|
# Notes: modifies input string to remove parsed objects
|
66
|
-
sub InflateStruct(
|
80
|
+
sub InflateStruct($$;$)
|
67
81
|
{
|
68
|
-
my ($obj, $delim) = @_;
|
82
|
+
my ($et, $obj, $delim) = @_;
|
69
83
|
my ($val, $warn, $part);
|
84
|
+
my $sfmt = $et->Options('StructFormat');
|
70
85
|
|
71
86
|
if ($$obj =~ s/^\s*\{//) {
|
72
87
|
my %struct;
|
73
|
-
|
88
|
+
for (;;) {
|
89
|
+
last unless $sfmt ? $$obj =~ s/^\s*"(.*?)"\s*://s :
|
90
|
+
$$obj =~ s/^\s*([-\w:]+#?)\s*=//s;
|
74
91
|
my $tag = $1;
|
75
|
-
my ($v, $w) = InflateStruct($obj, '}');
|
92
|
+
my ($v, $w) = InflateStruct($et, $obj, '}');
|
76
93
|
$warn = $w if $w and not $warn;
|
77
94
|
return(undef, $warn) unless defined $v;
|
78
95
|
$struct{$tag} = $v;
|
@@ -94,7 +111,7 @@ sub InflateStruct($;$)
|
|
94
111
|
} elsif ($$obj =~ s/^\s*\[//) {
|
95
112
|
my @list;
|
96
113
|
for (;;) {
|
97
|
-
my ($v, $w) = InflateStruct($obj, ']');
|
114
|
+
my ($v, $w) = InflateStruct($et, $obj, ']');
|
98
115
|
$warn = $w if $w and not $warn;
|
99
116
|
return(undef, $warn) unless defined $v;
|
100
117
|
push @list, $v;
|
@@ -105,20 +122,71 @@ sub InflateStruct($;$)
|
|
105
122
|
$val = \@list;
|
106
123
|
} else {
|
107
124
|
$$obj =~ s/^\s+//s; # remove leading whitespace
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
125
|
+
if ($sfmt) {
|
126
|
+
if ($$obj =~ s/^"//) {
|
127
|
+
$val = '';
|
128
|
+
while ($$obj =~ s/(.*?)"//) {
|
129
|
+
$val .= $1;
|
130
|
+
last unless $val =~ /([\\]+)$/ and length($1) & 0x01;
|
131
|
+
substr($val, -1, 1) = '"'; # (was an escaped quote)
|
132
|
+
}
|
133
|
+
if ($val =~ s/^base64://) {
|
134
|
+
$val = DecodeBase64($val);
|
135
|
+
} else {
|
136
|
+
# un-escape characters in JSON string
|
137
|
+
$val =~ s/\\(.)/$jsonEsc{$1}||'\\'.$1/egs;
|
138
|
+
}
|
139
|
+
} elsif ($$obj =~ s/^(true|false)\b//) {
|
140
|
+
$val = '"' . ucfirst($1) . '"';
|
141
|
+
} elsif ($$obj =~ s/^([+-]?(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?)//) {
|
142
|
+
$val = $1;
|
143
|
+
} else {
|
144
|
+
$warn or $warn = 'Unknown JSON object';
|
145
|
+
$val = '""';
|
146
|
+
}
|
147
|
+
} else {
|
148
|
+
# read scalar up to specified delimiter (or "," if not defined)
|
149
|
+
$delim = $delim ? "\\$delim|,|\\||\$" : ',|\\||$';
|
150
|
+
$val = '';
|
151
|
+
for (;;) {
|
152
|
+
$$obj =~ s/^(.*?)($delim)//s or last;
|
153
|
+
$val .= $1;
|
154
|
+
last unless $2;
|
155
|
+
$2 eq '|' or $$obj = $2 . $$obj, last;
|
156
|
+
$$obj =~ s/^(.)//s and $val .= $1; # add escaped character
|
157
|
+
}
|
117
158
|
}
|
118
159
|
}
|
119
160
|
return($val, $warn);
|
120
161
|
}
|
121
162
|
|
163
|
+
#------------------------------------------------------------------------------
|
164
|
+
# Escape string for JSON
|
165
|
+
# Inputs: 0) string, 1) flag to force numbers to be quoted too
|
166
|
+
# Returns: Escaped string (quoted if necessary)
|
167
|
+
sub EscapeJSON($;$)
|
168
|
+
{
|
169
|
+
my ($str, $quote) = @_;
|
170
|
+
unless ($quote) {
|
171
|
+
return 'null' unless defined $str;
|
172
|
+
# JSON boolean (true or false)
|
173
|
+
return lc($str) if $str =~ /^(true|false)$/i;
|
174
|
+
# JSON number (see json.org for numerical format)
|
175
|
+
# return $str if $str =~ /^-?(\d|[1-9]\d+)(\.\d+)?(e[-+]?\d+)?$/i;
|
176
|
+
# (these big numbers caused problems for some JSON parsers, so be more conservative)
|
177
|
+
return $str if $str =~ /^-?(\d|[1-9]\d{1,14})(\.\d{1,16})?(e[-+]?\d{1,3})?$/i;
|
178
|
+
}
|
179
|
+
return '""' unless defined $str;
|
180
|
+
# encode JSON string in base64 if necessary
|
181
|
+
return '"base64:' . EncodeBase64($str, 1) . '"' if Image::ExifTool::IsUTF8(\$str) < 0;
|
182
|
+
# escape special characters
|
183
|
+
$str =~ s/(["\t\n\r\\])/\\$jsonChar{$1}/sg;
|
184
|
+
$str =~ tr/\0//d; # remove all nulls
|
185
|
+
# escape other control characters with \u
|
186
|
+
$str =~ s/([\0-\x1f])/sprintf("\\u%.4X",ord $1)/sge;
|
187
|
+
return '"' . $str . '"'; # return the quoted string
|
188
|
+
}
|
189
|
+
|
122
190
|
#------------------------------------------------------------------------------
|
123
191
|
# Get XMP language code from tag name string
|
124
192
|
# Inputs: 0) tag name string
|