exiftool_vendored 13.36.0 → 13.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/Changes +23 -0
- data/bin/MANIFEST +5 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/build_geolocation +7 -3
- data/bin/exiftool +2 -2
- data/bin/lib/Image/ExifTool/Audible.pm +1 -1
- data/bin/lib/Image/ExifTool/BMP.pm +1 -1
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +15 -8
- data/bin/lib/Image/ExifTool/CBOR.pm +1 -1
- data/bin/lib/Image/ExifTool/Canon.pm +59 -5
- data/bin/lib/Image/ExifTool/CanonVRD.pm +1 -1
- data/bin/lib/Image/ExifTool/CaptureOne.pm +1 -1
- data/bin/lib/Image/ExifTool/DJI.pm +5 -5
- data/bin/lib/Image/ExifTool/DV.pm +1 -1
- data/bin/lib/Image/ExifTool/EXE.pm +3 -2
- data/bin/lib/Image/ExifTool/FLIF.pm +1 -1
- data/bin/lib/Image/ExifTool/FLIR.pm +3 -3
- data/bin/lib/Image/ExifTool/FlashPix.pm +1 -1
- data/bin/lib/Image/ExifTool/FujiFilm.pm +5 -4
- data/bin/lib/Image/ExifTool/GIF.pm +1 -1
- data/bin/lib/Image/ExifTool/GM.pm +1 -1
- data/bin/lib/Image/ExifTool/Geolocation.pm +3 -1
- data/bin/lib/Image/ExifTool/Geotag.pm +10 -2
- data/bin/lib/Image/ExifTool/GoPro.pm +5 -5
- data/bin/lib/Image/ExifTool/Google.pm +804 -0
- data/bin/lib/Image/ExifTool/H264.pm +1 -1
- data/bin/lib/Image/ExifTool/ICC_Profile.pm +1 -1
- data/bin/lib/Image/ExifTool/ID3.pm +3 -3
- data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
- data/bin/lib/Image/ExifTool/JSON.pm +1 -1
- data/bin/lib/Image/ExifTool/LIF.pm +1 -1
- data/bin/lib/Image/ExifTool/LNK.pm +2 -2
- data/bin/lib/Image/ExifTool/Lytro.pm +1 -1
- data/bin/lib/Image/ExifTool/M2TS.pm +2 -2
- data/bin/lib/Image/ExifTool/MPEG.pm +1 -1
- data/bin/lib/Image/ExifTool/MWG.pm +1 -1
- data/bin/lib/Image/ExifTool/MXF.pm +1 -1
- data/bin/lib/Image/ExifTool/MacOS.pm +2 -2
- data/bin/lib/Image/ExifTool/MakerNotes.pm +30 -7
- data/bin/lib/Image/ExifTool/Microsoft.pm +4 -4
- data/bin/lib/Image/ExifTool/Nikon.pm +4 -4
- data/bin/lib/Image/ExifTool/OOXML.pm +1 -1
- data/bin/lib/Image/ExifTool/Ogg.pm +1 -1
- data/bin/lib/Image/ExifTool/Olympus.pm +2 -1
- data/bin/lib/Image/ExifTool/Other.pm +1 -1
- data/bin/lib/Image/ExifTool/Panasonic.pm +1 -1
- data/bin/lib/Image/ExifTool/Pentax.pm +18 -7
- data/bin/lib/Image/ExifTool/Protobuf.pm +12 -6
- data/bin/lib/Image/ExifTool/Qualcomm.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +30 -8
- data/bin/lib/Image/ExifTool/README +7 -6
- data/bin/lib/Image/ExifTool/Rawzor.pm +1 -1
- data/bin/lib/Image/ExifTool/Reconyx.pm +375 -91
- data/bin/lib/Image/ExifTool/Samsung.pm +1 -1
- data/bin/lib/Image/ExifTool/Shortcuts.pm +8 -5
- data/bin/lib/Image/ExifTool/Sony.pm +18 -3
- data/bin/lib/Image/ExifTool/TagInfoXML.pm +3 -2
- data/bin/lib/Image/ExifTool/TagLookup.pm +5745 -5695
- data/bin/lib/Image/ExifTool/TagNames.pod +662 -509
- data/bin/lib/Image/ExifTool/Text.pm +1 -1
- data/bin/lib/Image/ExifTool/Trailer.pm +1 -1
- data/bin/lib/Image/ExifTool/WPG.pm +1 -1
- data/bin/lib/Image/ExifTool/WTV.pm +1 -1
- data/bin/lib/Image/ExifTool/XMP.pm +31 -30
- data/bin/lib/Image/ExifTool/XMP2.pl +0 -482
- data/bin/lib/Image/ExifTool/ZIP.pm +1 -1
- data/bin/lib/Image/ExifTool/iWork.pm +1 -1
- data/bin/lib/Image/ExifTool.pm +4 -4
- data/bin/lib/Image/ExifTool.pod +3 -3
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +4 -6
@@ -0,0 +1,804 @@
|
|
1
|
+
#------------------------------------------------------------------------------
|
2
|
+
# File: Google.pm
|
3
|
+
#
|
4
|
+
# Description: Google maker notes and XMP tags
|
5
|
+
#
|
6
|
+
# Revisions: 2025-09-17 - P. Harvey Created
|
7
|
+
#
|
8
|
+
# References: 1) https://github.com/jakiki6/ruminant/blob/master/ruminant/modules/images.py
|
9
|
+
#------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
package Image::ExifTool::Google;
|
12
|
+
|
13
|
+
use strict;
|
14
|
+
use vars qw($VERSION);
|
15
|
+
use Image::ExifTool qw(:DataAccess :Utils);
|
16
|
+
use Image::ExifTool::XMP;
|
17
|
+
|
18
|
+
$VERSION = '1.00';
|
19
|
+
|
20
|
+
sub ProcessHDRP($$$);
|
21
|
+
|
22
|
+
# default formats based on Google format size
|
23
|
+
my @formatName = ( undef, 'string', 'int16s', undef, 'int32s' );
|
24
|
+
|
25
|
+
my %sPose = (
|
26
|
+
STRUCT_NAME => 'Google Pose',
|
27
|
+
NAMESPACE => { Pose => 'http://ns.google.com/photos/dd/1.0/pose/' },
|
28
|
+
PositionX => { Writable => 'real', Groups => { 2 => 'Location' } },
|
29
|
+
PositionY => { Writable => 'real', Groups => { 2 => 'Location' } },
|
30
|
+
PositionZ => { Writable => 'real', Groups => { 2 => 'Location' } },
|
31
|
+
RotationX => { Writable => 'real', Groups => { 2 => 'Location' } },
|
32
|
+
RotationY => { Writable => 'real', Groups => { 2 => 'Location' } },
|
33
|
+
RotationZ => { Writable => 'real', Groups => { 2 => 'Location' } },
|
34
|
+
RotationW => { Writable => 'real', Groups => { 2 => 'Location' } },
|
35
|
+
Timestamp => {
|
36
|
+
Writable => 'integer',
|
37
|
+
Shift => 'Time',
|
38
|
+
Groups => { 2 => 'Time' },
|
39
|
+
ValueConv => 'ConvertUnixTime($val / 1000, 1, 3)',
|
40
|
+
ValueConvInv => 'int(GetUnixTime($val, 1) * 1000)',
|
41
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
42
|
+
PrintConvInv => '$self->InverseDateTime($val,undef,1)',
|
43
|
+
},
|
44
|
+
);
|
45
|
+
my %sEarthPose = (
|
46
|
+
STRUCT_NAME => 'Google EarthPose',
|
47
|
+
NAMESPACE => { EarthPose => 'http://ns.google.com/photos/dd/1.0/earthpose/' },
|
48
|
+
Latitude => {
|
49
|
+
Writable => 'real',
|
50
|
+
Groups => { 2 => 'Location' },
|
51
|
+
ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
52
|
+
ValueConvInv => '$val',
|
53
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
54
|
+
PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")',
|
55
|
+
},
|
56
|
+
Longitude => {
|
57
|
+
Writable => 'real',
|
58
|
+
Groups => { 2 => 'Location' },
|
59
|
+
ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
60
|
+
ValueConvInv => '$val',
|
61
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
|
62
|
+
PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")',
|
63
|
+
},
|
64
|
+
Altitude => {
|
65
|
+
Writable => 'real',
|
66
|
+
Groups => { 2 => 'Location' },
|
67
|
+
PrintConv => '"$val m"',
|
68
|
+
PrintConvInv => '$val=~s/\s*m$//;$val',
|
69
|
+
},
|
70
|
+
RotationX => { Writable => 'real', Groups => { 2 => 'Location' } },
|
71
|
+
RotationY => { Writable => 'real', Groups => { 2 => 'Location' } },
|
72
|
+
RotationZ => { Writable => 'real', Groups => { 2 => 'Location' } },
|
73
|
+
RotationW => { Writable => 'real', Groups => { 2 => 'Location' } },
|
74
|
+
Timestamp => {
|
75
|
+
Writable => 'integer',
|
76
|
+
Shift => 'Time',
|
77
|
+
Groups => { 2 => 'Time' },
|
78
|
+
ValueConv => 'ConvertUnixTime($val / 1000, 1, 3)',
|
79
|
+
ValueConvInv => 'int(GetUnixTime($val, 1) * 1000)',
|
80
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
81
|
+
PrintConvInv => '$self->InverseDateTime($val,undef,1)',
|
82
|
+
},
|
83
|
+
);
|
84
|
+
my %sVendorInfo = (
|
85
|
+
STRUCT_NAME => 'Google VendorInfo',
|
86
|
+
NAMESPACE => { VendorInfo => 'http://ns.google.com/photos/dd/1.0/vendorinfo/' },
|
87
|
+
Model => { },
|
88
|
+
Manufacturer => { },
|
89
|
+
Notes => { },
|
90
|
+
);
|
91
|
+
my %sAppInfo = (
|
92
|
+
STRUCT_NAME => 'Google AppInfo',
|
93
|
+
NAMESPACE => { AppInfo => 'http://ns.google.com/photos/dd/1.0/appinfo/' },
|
94
|
+
Application => { },
|
95
|
+
Version => { },
|
96
|
+
ItemURI => { },
|
97
|
+
);
|
98
|
+
|
99
|
+
# Google audio namespace
|
100
|
+
%Image::ExifTool::Google::GAudio = (
|
101
|
+
%Image::ExifTool::XMP::xmpTableDefaults,
|
102
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-GAudio', 2 => 'Audio' },
|
103
|
+
NAMESPACE => 'GAudio',
|
104
|
+
Data => {
|
105
|
+
Name => 'AudioData',
|
106
|
+
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
107
|
+
ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
|
108
|
+
},
|
109
|
+
Mime => { Name => 'AudioMimeType' },
|
110
|
+
);
|
111
|
+
|
112
|
+
# Google image namespace
|
113
|
+
%Image::ExifTool::Google::GImage = (
|
114
|
+
%Image::ExifTool::XMP::xmpTableDefaults,
|
115
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-GImage', 2 => 'Image' },
|
116
|
+
NAMESPACE => 'GImage',
|
117
|
+
Data => {
|
118
|
+
Name => 'ImageData',
|
119
|
+
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
120
|
+
ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
|
121
|
+
},
|
122
|
+
Mime => { Name => 'ImageMimeType' },
|
123
|
+
);
|
124
|
+
|
125
|
+
# Google panorama namespace properties
|
126
|
+
# (ref https://exiftool.org/forum/index.php/topic,4569.0.html)
|
127
|
+
%Image::ExifTool::Google::GPano = (
|
128
|
+
%Image::ExifTool::XMP::xmpTableDefaults,
|
129
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-GPano', 2 => 'Image' },
|
130
|
+
NAMESPACE => 'GPano',
|
131
|
+
NOTES => q{
|
132
|
+
Panorama tags written by Google Photosphere. See
|
133
|
+
L<https://developers.google.com/panorama/metadata/> for the specification.
|
134
|
+
},
|
135
|
+
UsePanoramaViewer => { Writable => 'boolean' },
|
136
|
+
CaptureSoftware => { },
|
137
|
+
StitchingSoftware => { },
|
138
|
+
ProjectionType => { },
|
139
|
+
PoseHeadingDegrees => { Writable => 'real' },
|
140
|
+
PosePitchDegrees => { Writable => 'real' },
|
141
|
+
PoseRollDegrees => { Writable => 'real' },
|
142
|
+
InitialViewHeadingDegrees => { Writable => 'real' },
|
143
|
+
InitialViewPitchDegrees => { Writable => 'real' },
|
144
|
+
InitialViewRollDegrees => { Writable => 'real' },
|
145
|
+
InitialHorizontalFOVDegrees => { Writable => 'real' },
|
146
|
+
InitialVerticalFOVDegrees => { Writable => 'real' },
|
147
|
+
FirstPhotoDate => { %Image::ExifTool::XMP::dateTimeInfo, Groups => { 2 => 'Time' } },
|
148
|
+
LastPhotoDate => { %Image::ExifTool::XMP::dateTimeInfo, Groups => { 2 => 'Time' } },
|
149
|
+
SourcePhotosCount => { Writable => 'integer' },
|
150
|
+
ExposureLockUsed => { Writable => 'boolean' },
|
151
|
+
CroppedAreaImageWidthPixels => { Writable => 'real' },
|
152
|
+
CroppedAreaImageHeightPixels => { Writable => 'real' },
|
153
|
+
FullPanoWidthPixels => { Writable => 'real' },
|
154
|
+
FullPanoHeightPixels => { Writable => 'real' },
|
155
|
+
CroppedAreaLeftPixels => { Writable => 'real' },
|
156
|
+
CroppedAreaTopPixels => { Writable => 'real' },
|
157
|
+
InitialCameraDolly => { Writable => 'real' },
|
158
|
+
# (the following have been observed, but are not in the specification)
|
159
|
+
LargestValidInteriorRectLeft => { Writable => 'real' },
|
160
|
+
LargestValidInteriorRectTop => { Writable => 'real' },
|
161
|
+
LargestValidInteriorRectWidth => { Writable => 'real' },
|
162
|
+
LargestValidInteriorRectHeight => { Writable => 'real' },
|
163
|
+
);
|
164
|
+
|
165
|
+
# Google Spherical Images namespace (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md)
|
166
|
+
%Image::ExifTool::Google::GSpherical = (
|
167
|
+
%Image::ExifTool::XMP::xmpTableDefaults,
|
168
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-GSpherical', 2 => 'Image' },
|
169
|
+
WRITE_GROUP => 'GSpherical', # write in special location for video files
|
170
|
+
NAMESPACE => 'GSpherical',
|
171
|
+
AVOID => 1,
|
172
|
+
NOTES => q{
|
173
|
+
Not actually XMP. These RDF/XML tags are used in Google spherical MP4
|
174
|
+
videos. These tags are written into the video track of MOV/MP4 files, and
|
175
|
+
not at the top level like other XMP tags. See
|
176
|
+
L<https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md>
|
177
|
+
for the specification.
|
178
|
+
},
|
179
|
+
# (avoid due to conflicts with XMP-GPano tags)
|
180
|
+
Spherical => { Writable => 'boolean' },
|
181
|
+
Stitched => { Writable => 'boolean' },
|
182
|
+
StitchingSoftware => { },
|
183
|
+
ProjectionType => { },
|
184
|
+
StereoMode => { },
|
185
|
+
SourceCount => { Writable => 'integer' },
|
186
|
+
InitialViewHeadingDegrees => { Writable => 'real' },
|
187
|
+
InitialViewPitchDegrees => { Writable => 'real' },
|
188
|
+
InitialViewRollDegrees => { Writable => 'real' },
|
189
|
+
Timestamp => {
|
190
|
+
Name => 'TimeStamp',
|
191
|
+
Groups => { 2 => 'Time' },
|
192
|
+
Writable => 'integer',
|
193
|
+
Shift => 'Time',
|
194
|
+
ValueConv => 'ConvertUnixTime($val)', #(NC)
|
195
|
+
ValueConvInv => 'GetUnixTime($val)',
|
196
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
197
|
+
PrintConvInv => '$self->InverseDateTime($val)',
|
198
|
+
},
|
199
|
+
FullPanoWidthPixels => { Writable => 'integer' },
|
200
|
+
FullPanoHeightPixels => { Writable => 'integer' },
|
201
|
+
CroppedAreaImageWidthPixels => { Writable => 'integer' },
|
202
|
+
CroppedAreaImageHeightPixels=> { Writable => 'integer' },
|
203
|
+
CroppedAreaLeftPixels => { Writable => 'integer' },
|
204
|
+
CroppedAreaTopPixels => { Writable => 'integer' },
|
205
|
+
);
|
206
|
+
|
207
|
+
# Google depthmap information (ref https://developers.google.com/depthmap-metadata/reference)
|
208
|
+
%Image::ExifTool::Google::GDepth = (
|
209
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-GDepth', 2 => 'Image' },
|
210
|
+
NAMESPACE => 'GDepth',
|
211
|
+
AVOID => 1, # (too many potential tag name conflicts)
|
212
|
+
NOTES => q{
|
213
|
+
Google depthmap information. See
|
214
|
+
L<https://developers.google.com/depthmap-metadata/> for the specification.
|
215
|
+
},
|
216
|
+
WRITABLE => 'string', # (default to string-type tags)
|
217
|
+
PRIORITY => 0,
|
218
|
+
Format => {
|
219
|
+
PrintConv => {
|
220
|
+
RangeInverse => 'RangeInverse',
|
221
|
+
RangeLinear => 'RangeLinear',
|
222
|
+
},
|
223
|
+
},
|
224
|
+
Near => { Writable => 'real' },
|
225
|
+
Far => { Writable => 'real' },
|
226
|
+
Mime => { },
|
227
|
+
Data => {
|
228
|
+
Name => 'DepthImage',
|
229
|
+
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
230
|
+
ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
|
231
|
+
},
|
232
|
+
Units => { },
|
233
|
+
MeasureType => {
|
234
|
+
PrintConv => {
|
235
|
+
OpticalAxis => 'OpticalAxis',
|
236
|
+
OpticalRay => 'OpticalRay',
|
237
|
+
},
|
238
|
+
},
|
239
|
+
ConfidenceMime => { },
|
240
|
+
Confidence => {
|
241
|
+
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
242
|
+
ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
|
243
|
+
},
|
244
|
+
Manufacturer=> { },
|
245
|
+
Model => { },
|
246
|
+
Software => { },
|
247
|
+
ImageWidth => { Writable => 'real' },
|
248
|
+
ImageHeight => { Writable => 'real' },
|
249
|
+
);
|
250
|
+
|
251
|
+
# Google focus namespace
|
252
|
+
%Image::ExifTool::Google::GFocus = (
|
253
|
+
%Image::ExifTool::XMP::xmpTableDefaults,
|
254
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-GFocus', 2 => 'Image' },
|
255
|
+
NAMESPACE => 'GFocus',
|
256
|
+
NOTES => 'Focus information found in Google depthmap images.',
|
257
|
+
BlurAtInfinity => { Writable => 'real' },
|
258
|
+
FocalDistance => { Writable => 'real' },
|
259
|
+
FocalPointX => { Writable => 'real' },
|
260
|
+
FocalPointY => { Writable => 'real' },
|
261
|
+
);
|
262
|
+
|
263
|
+
# Google camera namespace (ref PH)
|
264
|
+
%Image::ExifTool::Google::GCamera = (
|
265
|
+
%Image::ExifTool::XMP::xmpTableDefaults,
|
266
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-GCamera', 2 => 'Camera' },
|
267
|
+
NAMESPACE => 'GCamera',
|
268
|
+
NOTES => 'Camera information found in Google panorama images.',
|
269
|
+
BurstID => { },
|
270
|
+
BurstPrimary => { },
|
271
|
+
PortraitNote => { },
|
272
|
+
PortraitRequest => {
|
273
|
+
Writable => 'string', # (writable in encoded format)
|
274
|
+
Binary => 1,
|
275
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Google::HDRPMakerNote' },
|
276
|
+
},
|
277
|
+
PortraitVersion => { },
|
278
|
+
SpecialTypeID => { List => 'Bag' },
|
279
|
+
PortraitNote => { },
|
280
|
+
DisableAutoCreation => { List => 'Bag' },
|
281
|
+
DisableSuggestedAction => { List => 'Bag' }, #forum16147
|
282
|
+
hdrp_makernote => {
|
283
|
+
Name => 'HDRPMakerNote',
|
284
|
+
Writable => 'string', # (writable in encoded format)
|
285
|
+
Binary => 1,
|
286
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Google::HDRPMakerNote' },
|
287
|
+
},
|
288
|
+
MicroVideo => { Writable => 'integer' },
|
289
|
+
MicroVideoVersion => { Writable => 'integer' },
|
290
|
+
MicroVideoOffset => { Writable => 'integer' },
|
291
|
+
MicroVideoPresentationTimestampUs => { Writable => 'integer' },
|
292
|
+
shot_log_data => { #forum14108
|
293
|
+
Name => 'ShotLogData',
|
294
|
+
Writable => 'string', # (writable in encoded format)
|
295
|
+
IsProtobuf => 1,
|
296
|
+
Binary => 1,
|
297
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Google::ShotLogData' },
|
298
|
+
},
|
299
|
+
HdrPlusMakernote => {
|
300
|
+
Name => 'HDRPlusMakerNote',
|
301
|
+
Writable => 'string', # (writable in encoded format)
|
302
|
+
Binary => 1,
|
303
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Google::HDRPlusMakerNote' },
|
304
|
+
},
|
305
|
+
MotionPhoto => { Writable => 'integer' },
|
306
|
+
MotionPhotoVersion => { Writable => 'integer' },
|
307
|
+
MotionPhotoPresentationTimestampUs => { Writable => 'integer' },
|
308
|
+
);
|
309
|
+
|
310
|
+
# Google creations namespace (ref PH)
|
311
|
+
%Image::ExifTool::Google::GCreations = (
|
312
|
+
%Image::ExifTool::XMP::xmpTableDefaults,
|
313
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-GCreations', 2 => 'Camera' },
|
314
|
+
NAMESPACE => 'GCreations',
|
315
|
+
NOTES => 'Google creations tags.',
|
316
|
+
CameraBurstID => { },
|
317
|
+
Type => { Avoid => 1 },
|
318
|
+
);
|
319
|
+
|
320
|
+
# Google depth-map Device namespace (ref 13)
|
321
|
+
%Image::ExifTool::Google::Device = (
|
322
|
+
%Image::ExifTool::XMP::xmpTableDefaults,
|
323
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-Device', 2 => 'Camera' },
|
324
|
+
NAMESPACE => { Device => 'http://ns.google.com/photos/dd/1.0/device/' },
|
325
|
+
NOTES => q{
|
326
|
+
Google depth-map Device tags. See
|
327
|
+
L<https://developer.android.com/training/camera2/Dynamic-depth-v1.0.pdf> for
|
328
|
+
the specification.
|
329
|
+
},
|
330
|
+
Container => {
|
331
|
+
Struct => {
|
332
|
+
STRUCT_NAME => 'Google DeviceContainer',
|
333
|
+
NAMESPACE => { Container => 'http://ns.google.com/photos/dd/1.0/container/' },
|
334
|
+
Directory => {
|
335
|
+
List => 'Seq',
|
336
|
+
Struct => {
|
337
|
+
STRUCT_NAME => 'Google DeviceDirectory',
|
338
|
+
NAMESPACE => { Container => 'http://ns.google.com/photos/dd/1.0/container/' },
|
339
|
+
Item => {
|
340
|
+
Struct => {
|
341
|
+
STRUCT_NAME => 'Google DeviceItem',
|
342
|
+
NAMESPACE => { Item => 'http://ns.google.com/photos/dd/1.0/item/' },
|
343
|
+
# use this as a key to process Google trailer
|
344
|
+
Mime => { RawConv => '$$self{ProcessGoogleTrailer} = $val' },
|
345
|
+
Length => { Writable => 'integer' },
|
346
|
+
Padding => { Writable => 'integer' },
|
347
|
+
DataURI => { },
|
348
|
+
},
|
349
|
+
},
|
350
|
+
},
|
351
|
+
}
|
352
|
+
},
|
353
|
+
},
|
354
|
+
Profiles => {
|
355
|
+
List => 'Seq',
|
356
|
+
FlatName => '',
|
357
|
+
Struct => {
|
358
|
+
STRUCT_NAME => 'Google DeviceProfiles',
|
359
|
+
NAMESPACE => { Device => 'http://ns.google.com/photos/dd/1.0/device/' },
|
360
|
+
Profile => {
|
361
|
+
Struct => {
|
362
|
+
STRUCT_NAME => 'Google DeviceProfile',
|
363
|
+
NAMESPACE => { Profile => 'http://ns.google.com/photos/dd/1.0/profile/' },
|
364
|
+
CameraIndices => { List => 'Seq', Writable => 'integer' },
|
365
|
+
Type => { },
|
366
|
+
},
|
367
|
+
},
|
368
|
+
},
|
369
|
+
},
|
370
|
+
Cameras => {
|
371
|
+
List => 'Seq',
|
372
|
+
FlatName => '',
|
373
|
+
Struct => {
|
374
|
+
STRUCT_NAME => 'Google DeviceCameras',
|
375
|
+
NAMESPACE => { Device => 'http://ns.google.com/photos/dd/1.0/device/' },
|
376
|
+
Camera => {
|
377
|
+
Struct => {
|
378
|
+
STRUCT_NAME => 'Google DeviceCamera',
|
379
|
+
NAMESPACE => { Camera => 'http://ns.google.com/photos/dd/1.0/camera/' },
|
380
|
+
DepthMap => {
|
381
|
+
Struct => {
|
382
|
+
STRUCT_NAME => 'Google DeviceDepthMap',
|
383
|
+
NAMESPACE => { DepthMap => 'http://ns.google.com/photos/dd/1.0/depthmap/' },
|
384
|
+
ConfidenceURI => { },
|
385
|
+
DepthURI => { },
|
386
|
+
Far => { Writable => 'real' },
|
387
|
+
Format => { },
|
388
|
+
ItemSemantic=> { },
|
389
|
+
MeasureType => { },
|
390
|
+
Near => { Writable => 'real' },
|
391
|
+
Units => { },
|
392
|
+
Software => { },
|
393
|
+
FocalTableEntryCount => { Writable => 'integer' },
|
394
|
+
FocalTable => { }, # (base64)
|
395
|
+
},
|
396
|
+
},
|
397
|
+
Image => {
|
398
|
+
Struct => {
|
399
|
+
STRUCT_NAME => 'Google DeviceImage',
|
400
|
+
NAMESPACE => { Image => 'http://ns.google.com/photos/dd/1.0/image/' },
|
401
|
+
ItemSemantic=> { },
|
402
|
+
ItemURI => { },
|
403
|
+
},
|
404
|
+
},
|
405
|
+
ImagingModel => {
|
406
|
+
Struct => {
|
407
|
+
STRUCT_NAME => 'Google DeviceImagingModel',
|
408
|
+
NAMESPACE => { ImagingModel => 'http://ns.google.com/photos/dd/1.0/imagingmodel/' },
|
409
|
+
Distortion => { }, # (base64)
|
410
|
+
DistortionCount => { Writable => 'integer' },
|
411
|
+
FocalLengthX => { Writable => 'real' },
|
412
|
+
FocalLengthY => { Writable => 'real' },
|
413
|
+
ImageHeight => { Writable => 'integer' },
|
414
|
+
ImageWidth => { Writable => 'integer' },
|
415
|
+
PixelAspectRatio=> { Writable => 'real' },
|
416
|
+
PrincipalPointX => { Writable => 'real' },
|
417
|
+
PrincipalPointY => { Writable => 'real' },
|
418
|
+
Skew => { Writable => 'real' },
|
419
|
+
},
|
420
|
+
},
|
421
|
+
PointCloud => {
|
422
|
+
Struct => {
|
423
|
+
STRUCT_NAME => 'Google DevicePointCloud',
|
424
|
+
NAMESPACE => { PointCloud => 'http://ns.google.com/photos/dd/1.0/pointcloud/' },
|
425
|
+
PointCloud => { Writable => 'integer' },
|
426
|
+
Points => { },
|
427
|
+
Metric => { Writable => 'boolean' },
|
428
|
+
},
|
429
|
+
},
|
430
|
+
Pose => { Struct => \%sPose },
|
431
|
+
LightEstimate => {
|
432
|
+
Struct => {
|
433
|
+
STRUCT_NAME => 'Google DeviceLightEstimate',
|
434
|
+
NAMESPACE => { LightEstimate => 'http://ns.google.com/photos/dd/1.0/lightestimate/' },
|
435
|
+
ColorCorrectionR => { Writable => 'real' },
|
436
|
+
ColorCorrectionG => { Writable => 'real' },
|
437
|
+
ColorCorrectionB => { Writable => 'real' },
|
438
|
+
PixelIntensity => { Writable => 'real' },
|
439
|
+
},
|
440
|
+
},
|
441
|
+
VendorInfo => { Struct => \%sVendorInfo },
|
442
|
+
AppInfo => { Struct => \%sAppInfo },
|
443
|
+
Trait => { },
|
444
|
+
},
|
445
|
+
},
|
446
|
+
},
|
447
|
+
},
|
448
|
+
VendorInfo => { Struct => \%sVendorInfo },
|
449
|
+
AppInfo => { Struct => \%sAppInfo },
|
450
|
+
EarthPos => { Struct => \%sEarthPose },
|
451
|
+
Pose => { Struct => \%sPose },
|
452
|
+
Planes => {
|
453
|
+
List => 'Seq',
|
454
|
+
FlatName => '',
|
455
|
+
Struct => {
|
456
|
+
STRUCT_NAME => 'Google DevicePlanes',
|
457
|
+
NAMESPACE => { Device => 'http://ns.google.com/photos/dd/1.0/device/' },
|
458
|
+
Plane => {
|
459
|
+
Struct => {
|
460
|
+
STRUCT_NAME => 'Google DevicePlane',
|
461
|
+
NAMESPACE => { Plane => 'http://ns.google.com/photos/dd/1.0/plane/' },
|
462
|
+
Pose => { Struct => \%sPose },
|
463
|
+
ExtentX => { Writable => 'real' },
|
464
|
+
ExtentZ => { Writable => 'real' },
|
465
|
+
BoundaryVertexCount => { Writable => 'integer' },
|
466
|
+
Boundary => { },
|
467
|
+
},
|
468
|
+
},
|
469
|
+
},
|
470
|
+
},
|
471
|
+
);
|
472
|
+
|
473
|
+
# Google container tags (ref https://developer.android.com/guide/topics/media/platform/hdr-image-format)
|
474
|
+
# NOTE: The namespace prefix used by ExifTool is 'GContainer' instead of 'Container'
|
475
|
+
# dueo to a conflict with Google's depth-map Device 'Container' namespace!
|
476
|
+
# (see ../pics/GooglePixel8Pro.jpg sample image)
|
477
|
+
%Image::ExifTool::Google::GContainer = (
|
478
|
+
%Image::ExifTool::XMP::xmpTableDefaults,
|
479
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-GContainer', 2 => 'Image' },
|
480
|
+
NAMESPACE => 'GContainer',
|
481
|
+
NOTES => q{
|
482
|
+
Google Container namespace. ExifTool uses the prefix 'GContainer' instead
|
483
|
+
of 'Container' to avoid a conflict with the Google Device Container
|
484
|
+
namespace.
|
485
|
+
},
|
486
|
+
Directory => {
|
487
|
+
Name => 'ContainerDirectory',
|
488
|
+
FlatName => 'Directory',
|
489
|
+
List => 'Seq',
|
490
|
+
Struct => {
|
491
|
+
STRUCT_NAME => 'Google Directory',
|
492
|
+
Item => {
|
493
|
+
Namespace => 'GContainer',
|
494
|
+
Struct => {
|
495
|
+
STRUCT_NAME => 'Google Item',
|
496
|
+
# (use 'GItem' to avoid conflict with Google Device Container Item)
|
497
|
+
NAMESPACE => { GItem => 'http://ns.google.com/photos/1.0/container/item/'},
|
498
|
+
Mime => { RawConv => '$$self{ProcessGoogleTrailer} = $val' },
|
499
|
+
Semantic => { },
|
500
|
+
Length => { Writable => 'integer' },
|
501
|
+
Label => { },
|
502
|
+
Padding => { Writable => 'integer' },
|
503
|
+
URI => { },
|
504
|
+
},
|
505
|
+
},
|
506
|
+
},
|
507
|
+
},
|
508
|
+
);
|
509
|
+
|
510
|
+
# DHRP maker notes (ref PH)
|
511
|
+
%Image::ExifTool::Google::HDRPlusMakerNote = (
|
512
|
+
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
513
|
+
TAG_PREFIX => 'HDRPlusMakerNote',
|
514
|
+
PROCESS_PROC => \&ProcessHDRP,
|
515
|
+
VARS => { ID_FMT => 'str' },
|
516
|
+
NOTES => q{
|
517
|
+
Google protobuf-format HDR-Plus maker notes. Tag ID's are hierarchical
|
518
|
+
protobuf field numbers. Stored as base64-encoded, encrypted and gzipped
|
519
|
+
Protobuf data.
|
520
|
+
},
|
521
|
+
'1-1' => 'ImageName',
|
522
|
+
'1-2' => { Name => 'ImageData', Format => 'undef', Binary => 1 },
|
523
|
+
'2' => { Name => 'TimeLogText', Binary => 1 },
|
524
|
+
'3' => { Name => 'SummaryText', Binary => 1 },
|
525
|
+
'9-3' => { Name => 'FrameCount', Format => 'unsigned' },
|
526
|
+
# 9-4 - smaller for larger focal lengths
|
527
|
+
'9-36-1' => {
|
528
|
+
Name => 'CreateDate',
|
529
|
+
Groups => { 2 => 'Time' },
|
530
|
+
Format => 'unsigned',
|
531
|
+
Priority => 0, # (to give EXIF priority)
|
532
|
+
ValueConv => 'ConvertUnixTime($val, 1)',
|
533
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
534
|
+
},
|
535
|
+
'12-1' => { Name => 'DeviceMake', Groups => { 2 => 'Device' } },
|
536
|
+
'12-2' => { Name => 'DeviceModel', Groups => { 2 => 'Device' } },
|
537
|
+
'12-3' => { Name => 'DeviceCodename', Groups => { 2 => 'Device' } },
|
538
|
+
'12-4' => { Name => 'DeviceHardwareRevision', Groups => { 2 => 'Device' } },
|
539
|
+
'12-6' => { Name => 'HDRPSoftware', Groups => { 2 => 'Device' } },
|
540
|
+
'12-7' => { Name => 'AndroidRelease', Groups => { 2 => 'Device' } },
|
541
|
+
'12-8' => {
|
542
|
+
Name => 'SoftwareDate',
|
543
|
+
Groups => { 2 => 'Time' },
|
544
|
+
Format => 'unsigned',
|
545
|
+
ValueConv => 'ConvertUnixTime($val / 1000, 1, 3)',
|
546
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
547
|
+
},
|
548
|
+
'12-9' => { Name => 'Application', Groups => { 2 => 'Device' } },
|
549
|
+
'12-10' => { Name => 'AppVersion', Groups => { 2 => 'Device' } },
|
550
|
+
'12-12-1' => {
|
551
|
+
Name => 'ExposureTimeMin',
|
552
|
+
Groups => { 2 => 'Camera' },
|
553
|
+
Format => 'float',
|
554
|
+
ValueConv => '$val / 1000',
|
555
|
+
},
|
556
|
+
'12-12-2' => {
|
557
|
+
Name => 'ExposureTimeMax',
|
558
|
+
Groups => { 2 => 'Camera' },
|
559
|
+
Format => 'float',
|
560
|
+
ValueConv => '$val / 1000',
|
561
|
+
},
|
562
|
+
'12-13-1' => { Name => 'ISOMin', Format => 'float', Groups => { 2 => 'Camera' } }, # (NC)
|
563
|
+
'12-13-2' => { Name => 'ISOMax', Format => 'float', Groups => { 2 => 'Camera' } }, # (NC)
|
564
|
+
'12-14' => { Name => 'MaxAnalogISO', Format => 'float', Groups => { 2 => 'Camera' } }, # (NC)
|
565
|
+
);
|
566
|
+
|
567
|
+
%Image::ExifTool::Google::ShotLogData = (
|
568
|
+
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
569
|
+
TAG_PREFIX => 'ShotLogData',
|
570
|
+
PROCESS_PROC => \&ProcessHDRP,
|
571
|
+
VARS => { ID_FMT => 'str' },
|
572
|
+
NOTES => 'Stored as base64-encoded, encrypted and gzipped Protobuf data.',
|
573
|
+
2 => { Name => 'MeteringFrameCount', Format => 'unsigned' }, # (NC)
|
574
|
+
3 => { Name => 'OriginalPayloadFrameCount', Format => 'unsigned' }, # (NC)
|
575
|
+
# 1-6 - pure_fraction_of_pixels_from_long_exposure?
|
576
|
+
# 1-7 - weighted_fraction_of_pixels_from_long_exposure?
|
577
|
+
);
|
578
|
+
|
579
|
+
%Image::ExifTool::Google::HDRPMakerNote = (
|
580
|
+
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
581
|
+
TAG_PREFIX => '',
|
582
|
+
PROCESS_PROC => \&ProcessHDRP,
|
583
|
+
VARS => { LONG_TAGS => 1 },
|
584
|
+
NOTES => q{
|
585
|
+
Google text-based HDRP maker note tags. Stored as base64-encoded,
|
586
|
+
encrypted and gzipped text.
|
587
|
+
},
|
588
|
+
'InitParams' => { Name => 'InitParamsText', Binary => 1 },
|
589
|
+
'Logging metadata' => { Name => 'LoggingMetadataText', Binary => 1 },
|
590
|
+
'Merged image' => { Name => 'MergedImage', Binary => 1 },
|
591
|
+
'Finished image' => { Name => 'FinishedImage', Binary => 1 },
|
592
|
+
'Payload frame' => { Name => 'PayloadFrame', Binary => 1 },
|
593
|
+
'Payload metadata' => { Name => 'PayloadMetadataText', Binary => 1 },
|
594
|
+
'ShotLogData' => { Name => 'ShotLogDataText', Binary => 1 },
|
595
|
+
'ShotParams' => { Name => 'ShotParamsText', Binary => 1 },
|
596
|
+
'StaticMetadata' => { Name => 'StaticMetadataText', Binary => 1 },
|
597
|
+
'Summary' => { Name => 'SummaryText', Binary => 1 },
|
598
|
+
'Time log' => { Name => 'TimeLogText', Binary => 1 },
|
599
|
+
'Unused logging metadata' => { Name => 'UnusedLoggingMetadata', Binary => 1 },
|
600
|
+
'Rectiface' => { Name => 'RectifaceText', Binary => 1 },
|
601
|
+
'GoudaRequest' => { Name => 'GoudaRequestText', Binary => 1 },
|
602
|
+
ProcessingNotes => { },
|
603
|
+
);
|
604
|
+
|
605
|
+
%Image::ExifTool::Google::PortraitReq = (
|
606
|
+
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
607
|
+
TAG_PREFIX => '',
|
608
|
+
PROCESS_PROC => \&ProcessHDRP,
|
609
|
+
NOTES => q{
|
610
|
+
Google text-based PortraitRequest information. Stored as base64-encoded,
|
611
|
+
encrypted and gzipped text.
|
612
|
+
},
|
613
|
+
);
|
614
|
+
|
615
|
+
#------------------------------------------------------------------------------
|
616
|
+
# Read HDRP text-format maker note version 2
|
617
|
+
# Inputs: 0) ExifTool ref, 1) data ref
|
618
|
+
sub ProcessHDRPMakerNote($$)
|
619
|
+
{
|
620
|
+
my ($et, $dataPt) = @_;
|
621
|
+
my ($tag, $dat, $pos);
|
622
|
+
my $tagTbl = GetTagTable('Image::ExifTool::Google::HDRPMakerNote');
|
623
|
+
for (;;) {
|
624
|
+
my ($end, $last);
|
625
|
+
if ($$dataPt =~ /^ ?([A-Z].*)$/mg) {
|
626
|
+
$end = pos($$dataPt) - length($1);
|
627
|
+
} else {
|
628
|
+
$end = length($$dataPt);
|
629
|
+
$last = 1;
|
630
|
+
}
|
631
|
+
if ($tag) {
|
632
|
+
my $len = $end - ($pos + 1);
|
633
|
+
last if $len <= 0; # (just to be safe)
|
634
|
+
$et->HandleTag($tagTbl, $tag, substr($$dataPt, $pos + 1, $len), MakeTagInfo => 1);
|
635
|
+
}
|
636
|
+
last if $last;
|
637
|
+
$tag = $1;
|
638
|
+
unless ($tag =~ /:/ or $tag =~ /^\w+$/) {
|
639
|
+
$et->HandleTag($tagTbl, 'ProcessingNotes', $tag);
|
640
|
+
undef $tag;
|
641
|
+
next;
|
642
|
+
}
|
643
|
+
$pos = pos $$dataPt;
|
644
|
+
if ($tag =~ s/( \(base64\))?: ?(.*)// and $2) {
|
645
|
+
my $dat = $2;
|
646
|
+
$dat = Image::ExifTool::XMP::DecodeBase64($dat) if $1;
|
647
|
+
$et->HandleTag($tagTbl, $tag, $dat, MakeTagInfo => 1);
|
648
|
+
undef $tag;
|
649
|
+
}
|
650
|
+
}
|
651
|
+
}
|
652
|
+
|
653
|
+
#------------------------------------------------------------------------------
|
654
|
+
# Decode HDRP maker notes (ref https://github.com/jakiki6/ruminant/blob/master/ruminant/modules/images.py)
|
655
|
+
# Inputs: 0) ExifTool ref, 1) base64-encoded string, 2) tagInfo ref
|
656
|
+
# Returns: reference to decoded+decrypted+gunzipped data
|
657
|
+
# - also extracts protobuf info as separate tags when Unknown used if $$tagInfo{IsProtobuf} is set
|
658
|
+
sub ProcessHDRP($$$)
|
659
|
+
{
|
660
|
+
my ($et, $dirInfo, $tagTbl) = @_;
|
661
|
+
my $dataPt = $$dirInfo{DataPt};
|
662
|
+
my $tagInfo = $$dirInfo{TagInfo};
|
663
|
+
my $tagName = $tagInfo ? $$tagInfo{Name} : '';
|
664
|
+
my $verbose = $et->Options('Verbose');
|
665
|
+
my ($ver, $valPt);
|
666
|
+
|
667
|
+
if ($$dirInfo{DirStart}) {
|
668
|
+
my $dat = substr($$dataPt, $$dirInfo{DirStart}, $$dirInfo{DirLen});
|
669
|
+
$dataPt = \$dat;
|
670
|
+
}
|
671
|
+
if ($$dataPt =~ /^HDRP[\x02\x03]/) {
|
672
|
+
$valPt = $dataPt;
|
673
|
+
} else {
|
674
|
+
$et->VerboseDir($tagName, undef, length($$dataPt));
|
675
|
+
$et->VerboseDump($dataPt) if $verbose > 2;
|
676
|
+
$valPt = Image::ExifTool::XMP::DecodeBase64($$dataPt);
|
677
|
+
if ($verbose > 2) {
|
678
|
+
$et->VerboseDir("Base64-decoded $tagName", undef, length($$valPt));
|
679
|
+
$et->VerboseDump($valPt);
|
680
|
+
}
|
681
|
+
}
|
682
|
+
if ($$valPt =~ s/^HDRP([\x02\x03])//) {
|
683
|
+
$ver = ord($1);
|
684
|
+
} else {
|
685
|
+
$et->Warn('Unrecognized HDRP format');
|
686
|
+
return undef;
|
687
|
+
}
|
688
|
+
my $pad = (8 - (length($$valPt) % 8)) & 0x07;
|
689
|
+
$$valPt .= "\0" x $pad if $pad; # pad to an even 8 bytes
|
690
|
+
my @words = unpack('V*', $$valPt);
|
691
|
+
# my $key = 0x2515606b4a7791cd;
|
692
|
+
my ($hi, $lo) = ( 0x2515606b, 0x4a7791cd );
|
693
|
+
my $i = 0;
|
694
|
+
while ($i < @words) {
|
695
|
+
# (messy, but handle all 64-bit arithmetic with 32-bit backward
|
696
|
+
# compatibility -- no bit operations on any number > 0xffffffff)
|
697
|
+
# rotate the key
|
698
|
+
# $key ^= $key >> 12;
|
699
|
+
$lo ^= $lo >> 12 | ($hi & 0xfff) << 20;
|
700
|
+
$hi ^= $hi >> 12;
|
701
|
+
# $key ^= ($key << 25) & 0xffffffffffffffff;
|
702
|
+
$hi ^= ($hi & 0x7f) << 25 | $lo >> 7;
|
703
|
+
$lo ^= ($lo & 0x7f) << 25;
|
704
|
+
# $key ^= ($key >> 27) & 0xffffffffffffffff;
|
705
|
+
$lo ^= $lo >> 27 | ($hi & 0x7ffffff) << 5;
|
706
|
+
$hi ^= $hi >> 27;
|
707
|
+
# $key = ($key * 0x2545f4914f6cdd1d) & 0xffffffffffffffff;
|
708
|
+
# (multiply using 16-bit math to avoid overflowing 32-bit integers)
|
709
|
+
my @a = unpack('n*', pack('N*', $hi, $lo));
|
710
|
+
my @b = (0x2545, 0xf491, 0x4f6c, 0xdd1d);
|
711
|
+
my @c = (0) x 7;
|
712
|
+
my ($j, $k);
|
713
|
+
for ($j=0; $j<4; ++$j) {
|
714
|
+
for ($k=0; $k<4; ++$k) {
|
715
|
+
$c[$j+$k] += $a[$j] * $b[$k];
|
716
|
+
}
|
717
|
+
}
|
718
|
+
# (we only care about the low 32-bits, so don't bother with the upper 32)
|
719
|
+
for ($j=6; $j>=3; --$j) {
|
720
|
+
while ($c[$j] > 0xffffffff) {
|
721
|
+
++$c[$j-2];
|
722
|
+
$c[$j] -= 4294967296;
|
723
|
+
}
|
724
|
+
$c[$j-1] += $c[$j] >> 16;
|
725
|
+
$c[$j] &= 0xffff;
|
726
|
+
}
|
727
|
+
$hi = ($c[3] << 16) + $c[4];
|
728
|
+
$lo = ($c[5] << 16) + $c[6];
|
729
|
+
# apply the xor
|
730
|
+
$words[$i++] ^= $lo;
|
731
|
+
$words[$i++] ^= $hi;
|
732
|
+
}
|
733
|
+
my $result;
|
734
|
+
my $val = pack('V*', @words);
|
735
|
+
$val = substr($val,0,-$pad) if $pad; # remove padding
|
736
|
+
if ($verbose > 2) {
|
737
|
+
$et->VerboseDir("Decrypted $tagName", undef, length($val));
|
738
|
+
$et->VerboseDump(\$val);
|
739
|
+
}
|
740
|
+
if (eval { require IO::Uncompress::Gunzip }) {
|
741
|
+
my $buff;
|
742
|
+
if (IO::Uncompress::Gunzip::gunzip(\$val, \$buff)) {
|
743
|
+
if ($verbose > 2) {
|
744
|
+
$et->VerboseDir("Gunzipped $tagName", undef, length($buff));
|
745
|
+
$et->VerboseDump(\$buff);
|
746
|
+
}
|
747
|
+
if ($ver == 3 or ($tagInfo and $$tagInfo{IsProtobuf})) {
|
748
|
+
my %dirInfo = (
|
749
|
+
DataPt => \$buff,
|
750
|
+
DirName => $tagName,
|
751
|
+
);
|
752
|
+
require Image::ExifTool::Protobuf;
|
753
|
+
Image::ExifTool::Protobuf::ProcessProtobuf($et, \%dirInfo, $tagTbl);
|
754
|
+
} else {
|
755
|
+
ProcessHDRPMakerNote($et, \$buff);
|
756
|
+
}
|
757
|
+
$result = \$buff;
|
758
|
+
} else {
|
759
|
+
$et->Warn("Error inflating stream: $IO::Uncompress::Gunzip::GunzipError");
|
760
|
+
}
|
761
|
+
} else {
|
762
|
+
$et->Warn('Install IO::Uncompress::Gunzip to decode HDRP makernote');
|
763
|
+
}
|
764
|
+
return $result;
|
765
|
+
}
|
766
|
+
|
767
|
+
1; # end
|
768
|
+
|
769
|
+
__END__
|
770
|
+
|
771
|
+
=head1 NAME
|
772
|
+
|
773
|
+
Image::ExifTool::Google - Google maker notes and XMP tags
|
774
|
+
|
775
|
+
=head1 SYNOPSIS
|
776
|
+
|
777
|
+
This module is loaded automatically by Image::ExifTool when required.
|
778
|
+
|
779
|
+
=head1 DESCRIPTION
|
780
|
+
|
781
|
+
This module contains definitions required by Image::ExifTool to decode
|
782
|
+
Google maker notes and write Google XMP tags.
|
783
|
+
|
784
|
+
=head1 AUTHOR
|
785
|
+
|
786
|
+
Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
|
787
|
+
|
788
|
+
This library is free software; you can redistribute it and/or modify it
|
789
|
+
under the same terms as Perl itself.
|
790
|
+
|
791
|
+
=head1 REFERENCES
|
792
|
+
|
793
|
+
=over 4
|
794
|
+
|
795
|
+
=item L<https://github.com/jakiki6/ruminant/blob/master/ruminant/modules/images.py>
|
796
|
+
|
797
|
+
=back
|
798
|
+
|
799
|
+
=head1 SEE ALSO
|
800
|
+
|
801
|
+
L<Image::ExifTool::TagNames/Google Tags>,
|
802
|
+
L<Image::ExifTool(3pm)|Image::ExifTool>
|
803
|
+
|
804
|
+
=cut
|