exiftool_vendored 12.06.0 → 12.12.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of exiftool_vendored might be problematic. Click here for more details.

Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +96 -2
  3. data/bin/MANIFEST +5 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +43 -42
  7. data/bin/exiftool +156 -82
  8. data/bin/lib/Image/ExifTool.pm +22 -13
  9. data/bin/lib/Image/ExifTool.pod +59 -50
  10. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +11 -5
  11. data/bin/lib/Image/ExifTool/Canon.pm +202 -13
  12. data/bin/lib/Image/ExifTool/DarwinCore.pm +9 -3
  13. data/bin/lib/Image/ExifTool/EXE.pm +8 -5
  14. data/bin/lib/Image/ExifTool/GIF.pm +2 -2
  15. data/bin/lib/Image/ExifTool/Geotag.pm +30 -11
  16. data/bin/lib/Image/ExifTool/GoPro.pm +47 -30
  17. data/bin/lib/Image/ExifTool/IPTC.pm +1 -0
  18. data/bin/lib/Image/ExifTool/Import.pm +14 -11
  19. data/bin/lib/Image/ExifTool/JSON.pm +27 -4
  20. data/bin/lib/Image/ExifTool/MPF.pm +2 -2
  21. data/bin/lib/Image/ExifTool/MacOS.pm +153 -37
  22. data/bin/lib/Image/ExifTool/Matroska.pm +3 -1
  23. data/bin/lib/Image/ExifTool/Minolta.pm +5 -1
  24. data/bin/lib/Image/ExifTool/Nikon.pm +11 -3
  25. data/bin/lib/Image/ExifTool/Olympus.pm +8 -1
  26. data/bin/lib/Image/ExifTool/Panasonic.pm +12 -12
  27. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +1 -0
  28. data/bin/lib/Image/ExifTool/Pentax.pm +10 -3
  29. data/bin/lib/Image/ExifTool/QuickTime.pm +51 -16
  30. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +68 -45
  31. data/bin/lib/Image/ExifTool/README +5 -2
  32. data/bin/lib/Image/ExifTool/RSRC.pm +17 -11
  33. data/bin/lib/Image/ExifTool/Radiance.pm +7 -2
  34. data/bin/lib/Image/ExifTool/Sony.pm +56 -35
  35. data/bin/lib/Image/ExifTool/Stim.pm +2 -2
  36. data/bin/lib/Image/ExifTool/TagLookup.pm +5756 -5710
  37. data/bin/lib/Image/ExifTool/TagNames.pod +248 -49
  38. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +7 -6
  39. data/bin/lib/Image/ExifTool/Writer.pl +5 -3
  40. data/bin/lib/Image/ExifTool/XMP.pm +63 -18
  41. data/bin/lib/Image/ExifTool/XMP2.pl +1 -0
  42. data/bin/perl-Image-ExifTool.spec +42 -41
  43. data/lib/exiftool_vendored/version.rb +1 -1
  44. metadata +7 -7
@@ -15,7 +15,7 @@ use strict;
15
15
  use vars qw($VERSION);
16
16
  use Image::ExifTool::XMP;
17
17
 
18
- $VERSION = '1.04';
18
+ $VERSION = '1.05';
19
19
 
20
20
  my %dateTimeInfo = (
21
21
  # NOTE: Do NOT put "Groups" here because Groups hash must not be common!
@@ -44,14 +44,20 @@ my %event = (
44
44
  Groups => { 2 => 'Time' },
45
45
  Writable => 'string', # (so we can format this ourself)
46
46
  Shift => 'Time',
47
- # (pass straight through if this isn't a full date/time value)
47
+ # (allow date/time or just time value)
48
48
  ValueConv => 'Image::ExifTool::XMP::ConvertXMPDate($val)',
49
49
  PrintConv => '$self->ConvertDateTime($val)',
50
50
  ValueConvInv => 'Image::ExifTool::XMP::FormatXMPDate($val) or $val',
51
51
  PrintConvInv => q{
52
52
  my $v = $self->InverseDateTime($val,undef,1);
53
53
  undef $Image::ExifTool::evalWarning;
54
- return $v || $val;
54
+ return $v if $v;
55
+ # allow time-only values by adding dummy date (thanks Herb)
56
+ my $v = $self->InverseDateTime("2000:01:01 $val",undef,1);
57
+ undef $Image::ExifTool::evalWarning;
58
+ return $v if $v and $v =~ s/.* //; # strip off dummy date
59
+ $Image::ExifTool::evalWarning = 'Invalid date/time or time-only value (use HH:MM:SS[.ss][+/-HH:MM|Z])';
60
+ return undef;
55
61
  },
56
62
  },
57
63
  fieldNotes => { },
@@ -21,7 +21,7 @@ use strict;
21
21
  use vars qw($VERSION);
22
22
  use Image::ExifTool qw(:DataAccess :Utils);
23
23
 
24
- $VERSION = '1.16';
24
+ $VERSION = '1.17';
25
25
 
26
26
  sub ProcessPEResources($$);
27
27
  sub ProcessPEVersion($$);
@@ -1009,7 +1009,7 @@ sub ProcessPEDict($$)
1009
1009
  my $raf = $$dirInfo{RAF};
1010
1010
  my $dataPt = $$dirInfo{DataPt};
1011
1011
  my $dirLen = length($$dataPt);
1012
- my ($pos, @sections, %dirInfo);
1012
+ my ($pos, @sections, %dirInfo, $rsrcFound);
1013
1013
 
1014
1014
  # loop through all sections
1015
1015
  for ($pos=0; $pos+40<=$dirLen; $pos+=40) {
@@ -1019,14 +1019,16 @@ sub ProcessPEDict($$)
1019
1019
  my $offset = Get32u($dataPt, $pos + 20);
1020
1020
  # remember the section offsets for the VirtualAddress lookup later
1021
1021
  push @sections, { Base => $offset, Size => $size, VirtualAddress => $va };
1022
- # save details of the first resource section
1022
+ # save details of the first resource section (or .text if .rsrc not found, ref forum11465)
1023
+ next unless ($name eq ".rsrc\0\0\0" and not $rsrcFound and defined($rsrcFound = 1)) or
1024
+ ($name eq ".text\0\0\0" and not %dirInfo);
1023
1025
  %dirInfo = (
1024
1026
  RAF => $raf,
1025
1027
  Base => $offset,
1026
1028
  DirStart => 0, # (relative to Base)
1027
1029
  DirLen => $size,
1028
1030
  Sections => \@sections,
1029
- ) if $name eq ".rsrc\0\0\0" and not %dirInfo;
1031
+ );
1030
1032
  }
1031
1033
  # process the first resource section
1032
1034
  ProcessPEResources($et, \%dirInfo) or return 0 if %dirInfo;
@@ -1144,7 +1146,8 @@ sub ProcessEXE($$)
1144
1146
  my $fileSize = ($cp - ($cblp ? 1 : 0)) * 512 + $cblp;
1145
1147
  #(patch to accommodate observed 64-bit files)
1146
1148
  #return 0 if $fileSize < 0x40 or $fileSize < $lfarlc;
1147
- return 0 if $fileSize < 0x40;
1149
+ #return 0 if $fileSize < 0x40; (changed to warning in ExifTool 12.08)
1150
+ $et->Warn('Invalid file size in DOS header') if $fileSize < 0x40;
1148
1151
  # read the Windows NE, PE or LE (virtual device driver) header
1149
1152
  #if ($lfarlc == 0x40 and $fileSize > $lfanew + 2 and ...
1150
1153
  if ($raf->Seek($lfanew, 0) and $raf->Read($buff, 0x40) and $buff =~ /^(NE|PE|LE)/) {
@@ -20,7 +20,7 @@ use strict;
20
20
  use vars qw($VERSION);
21
21
  use Image::ExifTool qw(:DataAccess :Utils);
22
22
 
23
- $VERSION = '1.17';
23
+ $VERSION = '1.18';
24
24
 
25
25
  # road map of directory locations in GIF images
26
26
  my %gifMap = (
@@ -116,7 +116,7 @@ my %gifMap = (
116
116
  },
117
117
  5 => 'BackgroundColor',
118
118
  6 => {
119
- Name => 'AspectRatio',
119
+ Name => 'PixelAspectRatio',
120
120
  RawConv => '$val ? $val : undef',
121
121
  ValueConv => '($val + 15) / 64',
122
122
  },
@@ -13,6 +13,7 @@
13
13
  # 2016/07/13 - PH Added ability to geotag date/time only
14
14
  # 2019/07/02 - PH Added ability to read IMU CSV files
15
15
  # 2019/11/10 - PH Also write pitch to CameraElevationAngle
16
+ # 2020/12/01 - PH Added ability to read DJI CSV log files
16
17
  #
17
18
  # References: 1) http://www.topografix.com/GPX/1/1/
18
19
  # 2) http://www.gpsinformation.org/dale/nmea.htm#GSA
@@ -27,7 +28,7 @@ use vars qw($VERSION);
27
28
  use Image::ExifTool qw(:Public);
28
29
  use Image::ExifTool::GPS;
29
30
 
30
- $VERSION = '1.62';
31
+ $VERSION = '1.64';
31
32
 
32
33
  sub JITTER() { return 2 } # maximum time jitter
33
34
 
@@ -133,7 +134,7 @@ sub LoadTrackLog($$;$)
133
134
  my ($et, $val) = @_;
134
135
  my ($raf, $from, $time, $isDate, $noDate, $noDateChanged, $lastDate, $dateFlarm);
135
136
  my ($nmeaStart, $fixSecs, @fixTimes, $lastFix, %nmea, @csvHeadings);
136
- my ($canCut, $cutPDOP, $cutHDOP, $cutSats, $e0, $e1, @tmp);
137
+ my ($canCut, $cutPDOP, $cutHDOP, $cutSats, $e0, $e1, @tmp, $trackFile, $trackTime);
137
138
 
138
139
  unless (eval { require Time::Local }) {
139
140
  return 'Geotag feature requires Time::Local installed';
@@ -159,6 +160,7 @@ sub LoadTrackLog($$;$)
159
160
  } else {
160
161
  # $val is track file name
161
162
  if ($et->Open(\*EXIFTOOL_TRKFILE, $val)) {
163
+ $trackFile = $val;
162
164
  $raf = new File::RandomAccess(\*EXIFTOOL_TRKFILE);
163
165
  unless ($raf->Read($_, 256)) {
164
166
  close EXIFTOOL_TRKFILE;
@@ -201,6 +203,8 @@ sub LoadTrackLog($$;$)
201
203
  my $skipped = 0;
202
204
  my $lastSecs = 0;
203
205
  my $fix = { };
206
+ my $csvDelim = $et->Options('CSVDelim');
207
+ $csvDelim = ',' unless defined $csvDelim;
204
208
  my (@saveFix, $timeSpan);
205
209
  for (;;) {
206
210
  $raf->ReadLine($_) or last;
@@ -217,7 +221,7 @@ sub LoadTrackLog($$;$)
217
221
  # (don't set format yet because we want to read HFDTE first)
218
222
  $nmeaStart = 'B' ;
219
223
  next;
220
- } elsif (/^HFDTE(\d{2})(\d{2})(\d{2})/) {
224
+ } elsif (/^HFDTE(?:DATE:)?(\d{2})(\d{2})(\d{2})/) {
221
225
  my $year = $3 + ($3 >= 70 ? 1900 : 2000);
222
226
  $dateFlarm = Time::Local::timegm(0,0,0,$1,$2-1,$year);
223
227
  $nmeaStart = 'B' ;
@@ -230,19 +234,31 @@ sub LoadTrackLog($$;$)
230
234
  $format = 'Winplus';
231
235
  } elsif (/^\s*\d+\s+.*\sypr\s*$/ and (@tmp=split) == 12) {
232
236
  $format = 'Bramor';
233
- } elsif (/\b(GPS)?Date/i and /\b(GPS)?(Date)?Time/i and /,/) {
237
+ } elsif (((/\b(GPS)?Date/i and /\b(GPS)?(Date)?Time/i) or /\bTime\(seconds\)/i) and /\Q$csvDelim/) {
234
238
  chomp;
235
- @csvHeadings = split ',';
239
+ @csvHeadings = split /\Q$csvDelim/;
236
240
  $format = 'CSV';
237
241
  # convert recognized headings to our parameter names
238
242
  foreach (@csvHeadings) {
239
243
  my $param;
240
244
  s/^GPS ?//; # remove leading "GPS" to simplify regex patterns
241
- if (/^Date ?Time/i) { # ExifTool addition
245
+ if (/^Time ?\(seconds\)$/i) { # DJI
246
+ # DJI CSV log files have a column "Time(seconds)" which is seconds since
247
+ # the start of the flight. The date/time is obtained from the file name.
248
+ $param = 'runtime';
249
+ if ($trackFile and $trackFile =~ /(\d{4})-(\d{2})-(\d{2})[^\/]+(\d{2})-(\d{2})-(\d{2})[^\/]*$/) {
250
+ $trackTime = Image::ExifTool::TimeLocal($6,$5,$4,$3,$2-1,$1);
251
+ my $utc = PrintFixTime($trackTime);
252
+ my $tzs = Image::ExifTool::TimeZoneString([$6,$5,$4,$3,$2-1,$1-1900],$trackTime);
253
+ $et->VPrint(2, " DJI start time: $utc (local timezone is $tzs)\n");
254
+ } else {
255
+ return 'Error getting start time from file name for DJI CSV track file';
256
+ }
257
+ } elsif (/^Date ?Time/i) { # ExifTool addition
242
258
  $param = 'datetime';
243
259
  } elsif (/^Date/i) {
244
260
  $param = 'date';
245
- } elsif (/^Time/i) {
261
+ } elsif (/^Time(?! ?\(text\))/i) { # (ignore DJI "Time(text)" column)
246
262
  $param = 'time';
247
263
  } elsif (/^(Pos)?Lat/i) {
248
264
  $param = 'lat';
@@ -423,7 +439,7 @@ DoneFix: $isDate = 1;
423
439
  goto DoneFix; # save this fix
424
440
  } elsif ($format eq 'CSV') {
425
441
  chomp;
426
- my @vals = split ',';
442
+ my @vals = split /\Q$csvDelim/;
427
443
  #
428
444
  # CSV format output of GPS/IMU POS system
429
445
  # Date* - date in DD/MM/YYYY format
@@ -435,7 +451,7 @@ DoneFix: $isDate = 1;
435
451
  # [Angle]Pitch* - pitch angle in degrees
436
452
  # [Angle]Roll* - roll angle in degrees
437
453
  # (ExifTool enhancements allow for standard tag names or descriptions as the column headings,
438
- # add support for time zones and flexible coordinates, and allow a new DateTime column)
454
+ # add support for time zones and flexible coordinates, and allow new DateTime and Shift columns)
439
455
  #
440
456
  my ($param, $date, $secs);
441
457
  foreach $param (@csvHeadings) {
@@ -463,6 +479,9 @@ DoneFix: $isDate = 1;
463
479
  }
464
480
  } elsif ($param eq 'lat' or $param eq 'lon') {
465
481
  $$fix{$param} = Image::ExifTool::GPS::ToDegrees($val, 1);
482
+ } elsif ($param eq 'runtime') {
483
+ $date = $trackTime;
484
+ $secs = $val;
466
485
  } else {
467
486
  $$fix{$param} = $val;
468
487
  }
@@ -1378,8 +1397,8 @@ This module is used by Image::ExifTool
1378
1397
  This module loads GPS track logs, interpolates to determine position based
1379
1398
  on time, and sets new GPS values for geotagging images. Currently supported
1380
1399
  formats are GPX, NMEA RMC/GGA/GLL, KML, IGC, Garmin XML and TCX, Magellan
1381
- PMGNTRK, Honeywell PTNTHPR, Winplus Beacon text, IMU CSV, and Bramor gEO log
1382
- files.
1400
+ PMGNTRK, Honeywell PTNTHPR, Winplus Beacon text, IMU CSV, DJI CSV, and
1401
+ Bramor gEO log files.
1383
1402
 
1384
1403
  Methods in this module should not be called directly. Instead, the Geotag
1385
1404
  feature is accessed by writing the values of the ExifTool Geotag, Geosync
@@ -16,7 +16,7 @@ use vars qw($VERSION);
16
16
  use Image::ExifTool qw(:DataAccess :Utils);
17
17
  use Image::ExifTool::QuickTime;
18
18
 
19
- $VERSION = '1.04';
19
+ $VERSION = '1.06';
20
20
 
21
21
  sub ProcessGoPro($$$);
22
22
  sub ProcessString($$$);
@@ -77,6 +77,9 @@ my %addUnits = (
77
77
  Notes => 'accelerator readings in m/s2',
78
78
  Binary => 1,
79
79
  },
80
+ # ANGX (GPMF-GEOC) - seen -0.05 (fmt d, Max)
81
+ # ANGY (GPMF-GEOC) - seen 179.9 (fmt d, Max)
82
+ # ANGZ (GPMF-GEOC) - seen 0.152 (fmt d, Max)
80
83
  ALLD => 'AutoLowLightDuration', #1 (gpmd) (untested)
81
84
  # APTO (GPMF) - seen: 'RAW', 'DYNM' (fmt c)
82
85
  ATTD => { #PH (Karma)
@@ -105,16 +108,14 @@ my %addUnits = (
105
108
  },
106
109
  # BRID (GPMF) - seen: 0 (fmt B)
107
110
  # BROD (GPMF) - seen: 'ASK','' (fmt c)
111
+ # CALH (GPMF-GEOC) - seen 3040 (fmt L, Max)
112
+ # CALW (GPMF-GEOC) - seen 4056 (fmt L, Max)
108
113
  CASN => 'CameraSerialNumber', #PH (GPMF - seen: 'C3221324545448', fmt c)
109
- # CINF (GPMF) - seen: 0x67376be7709bc8876a8baf3940908618, 0xe230988539b30cf5f016627ae8fc5395 (fmt B) (Camera INFormation?)
110
- # CMOD (GPMF) - seen: 12,13,17 [13 time-laps video, 17 JPEG] (fmt B)
111
- CYTS => { #PH (Karma)
112
- Name => 'CoyoteStatus',
113
- # UNIT=s,,,,,rad,rad,rad,,
114
- # TYPE=LLLLLfffBB
115
- # SCAL=1000 1 1 1 1 1 1 1 1 1
116
- Binary => 1,
117
- },
114
+ # CINF (GPMF) - seen: 0x67376be7709bc8876a8baf3940908618, 0xe230988539b30cf5f016627ae8fc5395,
115
+ # 0x8bcbe424acc5b37d7d77001635198b3b (fmt B) (Camera INFormation?)
116
+ # CMOD (GPMF) - seen: 12,13,17 [12 360 video, 13 time-laps video, 17 JPEG] (fmt B)
117
+ # CRTX (GPMF-BACK/FRNT) - double[1]
118
+ # CRTY (GPMF-BACK/FRNT) - double[1]
118
119
  CSEN => { #PH (Karma)
119
120
  Name => 'CoyoteSense',
120
121
  # UNIT=s,rad/s,rad/s,rad/s,g,g,g,,,,
@@ -122,13 +123,27 @@ my %addUnits = (
122
123
  # SCAL=1000 1 1 1 1 1 1 1 1 1 1
123
124
  Binary => 1,
124
125
  },
126
+ CYTS => { #PH (Karma)
127
+ Name => 'CoyoteStatus',
128
+ # UNIT=s,,,,,rad,rad,rad,,
129
+ # TYPE=LLLLLfffBB
130
+ # SCAL=1000 1 1 1 1 1 1 1 1 1
131
+ Binary => 1,
132
+ },
125
133
  DEVC => { #PH (gpmd,GPMF, fmt \0)
126
134
  Name => 'DeviceContainer',
127
135
  SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
128
- },
129
- # DVID (GPMF) - DeviceID; seen: 1 (fmt L), HLMT (fmt F)
136
+ # (Max) DVID=1,DVNM='Global Settings',VERS,FMWR,LINF,CINF,CASN,MINF,MUID,CMOD,MTYP,OREN,
137
+ # DZOM,DZST,SMTR,PRTN,PTWB,PTSH,PTCL,EXPT,PIMX,PIMN,PTEV,RATE,SROT,ZFOV,VLTE,VLTA,
138
+ # EISE,EISA,AUPT,AUDO,BROD,BRID,PVUL,PRJT,SOFF
139
+ # (Max) DVID='GEOC',DVNM='Geometry Calibrations',SHFX,SHFY,SHFZ,ANGX,ANGY,ANGZ,CALW,CALH
140
+ # (Max) DVID='BACK',DVNM='Back Lens',KLNS,CTRX,CTRY,MFOV,SFTR
141
+ # (Max) DVID='FRNT',DVNM='Front Lens',KLNS,CTRX,CTRY,MFOV,SFTR
142
+ # (Max) DVID='HLMT',DVNM='Highlights'
143
+ },
144
+ # DVID (GPMF) - DeviceID; seen: 1 (fmt L), HLMT (fmt F), GEOC (fmt F), 'BACK' (fmt F, Max)
130
145
  DVID => { Name => 'DeviceID', Unknown => 1 }, #2 (gpmd)
131
- # DVNM (GPMF) seen: 'Video Global Settings' (fmt c), 'Highlights' (fmt c)
146
+ # DVNM (GPMF) seen: 'Video Global Settings' (fmt c), 'Highlights' (fmt c), 'Geometry Calibrations' (Max)
132
147
  # DVNM (gpmd) seen: 'Camera' (Hero5), 'Hero6 Black' (Hero6), 'GoPro Karma v1.0' (Karma)
133
148
  DVNM => 'DeviceName', #PH (n/c)
134
149
  DZOM => { #PH (GPMF - seen: 'Y', fmt c)
@@ -136,10 +151,10 @@ my %addUnits = (
136
151
  PrintConv => { N => 'No', Y => 'Yes' },
137
152
  },
138
153
  # DZST (GPMF) - seen: 0 (fmt L) (something to do with digital zoom maybe?)
139
- EISA => { #PH (GPMF) - seen: 'Y','N', 'HS EIS' (fmt c) [N was for a time-lapse video]
154
+ EISA => { #PH (GPMF) - seen: 'Y','N','HS EIS','N/A' (fmt c) [N was for a time-lapse video]
140
155
  Name => 'ElectronicImageStabilization',
141
156
  },
142
- # EISE (GPMF) - seen: 'Y' (fmt c)
157
+ # EISE (GPMF) - seen: 'Y','N' (fmt c)
143
158
  EMPT => { Name => 'Empty', Unknown => 1 }, #2 (gpmd)
144
159
  ESCS => { #PH (Karma)
145
160
  Name => 'EscapeStatus',
@@ -215,7 +230,8 @@ my %addUnits = (
215
230
  RawConv => '$val', # necessary to use scaled value instead of raw data as subdir data
216
231
  SubDirectory => { TagTable => 'Image::ExifTool::GoPro::KBAT' },
217
232
  },
218
- # LINF (GPMF) - seen: LAJ7061916601668, C3341326002180 (fmt c) (Lens INFormation?)
233
+ # KLNS (GPMF-BACK/FRNT) - double[5] (fmt d, Max)
234
+ # LINF (GPMF) - seen: LAJ7061916601668,C3341326002180,C33632245450981 (fmt c) (Lens INFormation?)
219
235
  LNED => { #PH (Karma)
220
236
  Name => 'LocalPositionNED',
221
237
  # UNIT=s,m,m,m,m/s,m/s,m/s
@@ -224,12 +240,13 @@ my %addUnits = (
224
240
  Binary => 1,
225
241
  },
226
242
  MAGN => 'Magnetometer', #1 (gpmd) (units of uT)
243
+ # MFOV (GPMF-BACK/FRNT) - seen: 100 (fmt d, Max)
227
244
  MINF => { #PH (GPMF - seen: HERO6 Black, fmt c)
228
245
  Name => 'Model',
229
246
  Groups => { 2 => 'Camera' },
230
247
  Description => 'Camera Model Name',
231
248
  },
232
- # MTYP (GPMF) - seen: 0,1,11 [1 for time-lapse video, 11 for JPEG] (fmt B)
249
+ # MTYP (GPMF) - seen: 0,1,5,11 [1 for time-lapse video, 5 for 360 video, 11 for JPEG] (fmt B)
233
250
  # MUID (GPMF) - seen: 3882563431 2278071152 967805802 411471936 0 0 0 0 (fmt L)
234
251
  OREN => { #PH (GPMF - seen: 'U', fmt c)
235
252
  Name => 'AutoRotation',
@@ -245,7 +262,7 @@ my %addUnits = (
245
262
  PIMX => 'AutoISOMax', #PH (GPMF - seen: 1600, fmt L)
246
263
  # PRAW (APP6) - seen: 0, 'N', 'Y' (fmt c)
247
264
  PRES => 'PhotoResolution', #PH (APP6 - seen: '12MP_W')
248
- # PRJT (APP6) - seen: 'GPRO' (fmt F, Hero8)
265
+ # PRJT (APP6) - seen: 'GPRO','EACO' (fmt F, Hero8, Max)
249
266
  PRTN => { #PH (GPMF - seen: 'N', fmt c)
250
267
  Name => 'ProTune',
251
268
  PrintConv => {
@@ -257,7 +274,7 @@ my %addUnits = (
257
274
  PTEV => 'ExposureCompensation', #PH (GPMF - seen: '0.0', fmt c)
258
275
  PTSH => 'Sharpness', #PH (GPMF - seen: 'HIGH', fmt c)
259
276
  PTWB => 'WhiteBalance', #PH (GPMF - seen: 'AUTO', fmt c)
260
- # PVUL (APP6) - seen: 'F' (fmt c, Hero8)
277
+ # PVUL (APP6) - seen: 'F' (fmt c, Hero8, Max)
261
278
  RATE => 'Rate', #PH (GPMF - seen: '0_5SEC', fmt c; APP6 - seen: '4_1SEC')
262
279
  RMRK => { #2 (gpmd)
263
280
  Name => 'Comments',
@@ -274,6 +291,10 @@ my %addUnits = (
274
291
  # SCAL=1000 0.00999999977648258 0.00999999977648258 100
275
292
  %addUnits,
276
293
  },
294
+ # SFTR (GPMF-BACK/FRNT) - seen 0.999,1.00004 (fmt d, Max)
295
+ # SHFX (GPMF-GEOC) - seen 22.92 (fmt d, Max)
296
+ # SHFY (GPMF-GEOC) - seen 0.123 (fmt d, Max)
297
+ # SHFZ (GPMF-GEOC) - seen 36.06 (fmt d, Max)
277
298
  SHUT => { #2 (gpmd)
278
299
  Name => 'ExposureTimes',
279
300
  PrintConv => q{
@@ -295,7 +316,8 @@ my %addUnits = (
295
316
  ValueConv => '$self->Decode($val, "Latin")',
296
317
  },
297
318
  # SMTR (GPMF) - seen: 'N' (fmt c)
298
- # SOFF (APP6) - seen: 0 (fmt L, Hero8)
319
+ # SOFF (APP6) - seen: 0 (fmt L, Hero8, Max)
320
+ # SROT (GPMF) - seen 20.60 (fmt f, Max)
299
321
  STMP => { #1 (gpmd)
300
322
  Name => 'TimeStamp',
301
323
  ValueConv => '$val / 1e6',
@@ -338,7 +360,10 @@ my %addUnits = (
338
360
  Unknown => 1,
339
361
  ValueConv => '$self->Decode($val, "Latin")',
340
362
  },
341
- # VERS (APP6) - seen: '7 6 4' (fmt B, Hero8)
363
+ VERS => {
364
+ Name => 'MetadataVersion',
365
+ PrintConv => '$val =~ tr/ /./; $val',
366
+ },
342
367
  VFOV => { #PH (GPMF - seen: 'W', fmt c)
343
368
  Name => 'FieldOfView',
344
369
  PrintConv => {
@@ -360,7 +385,7 @@ my %addUnits = (
360
385
  Name => 'WhiteBalanceRGB',
361
386
  Binary => 1,
362
387
  },
363
- # ZFOV (APP6) - seen: 148.34 (fmt f, Hero8)
388
+ # ZFOV (APP6,GPMF) - seen: 148.34, 0 (fmt f, Hero8, Max)
364
389
  );
365
390
 
366
391
  # GoPro GPS5 tags (ref 2) (Hero5,Hero6)
@@ -602,14 +627,6 @@ sub ProcessGoPro($$$)
602
627
  my $unknown = $verbose || $et->Options('Unknown');
603
628
  my ($size, $type, $unit, $scal, $setGroup0);
604
629
 
605
- # the Rove Stealth 4K writes encrypted text here, so check for this first
606
- # (really should check for this before loading GoPro module, but I was lazy) PHIL
607
- if ($$dataPt =~ /^\0\0\xf2\xe1\xf0\xeeTT/) {
608
- $et->VerboseDir('gpmd encrypted text', undef, length($$dataPt));
609
- my $strmTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
610
- Image::ExifTool::QuickTime::Process_text($et, $strmTbl, $dataPt);
611
- return 1;
612
- }
613
630
  $et->VerboseDir($$dirInfo{DirName} || 'GPMF', undef, $dirEnd-$pos) if $verbose;
614
631
  if ($pos) {
615
632
  my $parent = $$dirInfo{Parent};
@@ -497,6 +497,7 @@ my %fileFormat = (
497
497
  103 => {
498
498
  Name => 'OriginalTransmissionReference',
499
499
  Format => 'string[0,32]',
500
+ Notes => 'now used as a job identifier',
500
501
  },
501
502
  105 => {
502
503
  Name => 'Headline',
@@ -12,25 +12,26 @@ require Exporter;
12
12
 
13
13
  use vars qw($VERSION @ISA @EXPORT_OK);
14
14
 
15
- $VERSION = '1.09';
15
+ $VERSION = '1.10';
16
16
  @ISA = qw(Exporter);
17
17
  @EXPORT_OK = qw(ReadCSV ReadJSON);
18
18
 
19
19
  sub ReadJSONObject($;$);
20
20
 
21
- my %unescapeJSON = ( 't'=>"\t", 'n'=>"\n", 'r'=>"\r" );
21
+ my %unescapeJSON = ( 't'=>"\t", 'n'=>"\n", 'r'=>"\r", 'b' => "\b", 'f' => "\f" );
22
22
  my $charset;
23
23
 
24
24
  #------------------------------------------------------------------------------
25
25
  # Read CSV file
26
- # Inputs: 0) CSV file name, file ref or RAF ref, 1) database hash ref, 2) missing tag value
26
+ # Inputs: 0) CSV file name, file ref or RAF ref, 1) database hash ref,
27
+ # 2) missing tag value, 3) delimiter if other than ','
27
28
  # Returns: undef on success, or error string
28
29
  # Notes: There are various flavours of CSV, but here we assume that only
29
30
  # double quotes are escaped, and they are escaped by doubling them
30
- sub ReadCSV($$;$)
31
+ sub ReadCSV($$;$$)
31
32
  {
32
33
  local ($_, $/);
33
- my ($file, $database, $missingValue) = @_;
34
+ my ($file, $database, $missingValue, $delim) = @_;
34
35
  my ($buff, @tags, $found, $err, $raf, $openedFile);
35
36
 
36
37
  if (UNIVERSAL::isa($file, 'File::RandomAccess')) {
@@ -45,6 +46,7 @@ sub ReadCSV($$;$)
45
46
  $openedFile = 1;
46
47
  $raf = new File::RandomAccess(\*CSVFILE);
47
48
  }
49
+ $delim = ',' unless defined $delim;
48
50
  # set input record separator by first newline found in the file
49
51
  # (safe because first line should contain only tag names)
50
52
  while ($raf->Read($buff, 65536)) {
@@ -53,18 +55,18 @@ sub ReadCSV($$;$)
53
55
  $raf->Seek(0,0);
54
56
  while ($raf->ReadLine($buff)) {
55
57
  my (@vals, $v, $i, %fileInfo);
56
- my @toks = split ',', $buff;
58
+ my @toks = split /\Q$delim/, $buff;
57
59
  while (@toks) {
58
60
  ($v = shift @toks) =~ s/^ +//; # remove leading spaces
59
61
  if ($v =~ s/^"//) {
60
62
  # quoted value must end in an odd number of quotes
61
63
  while ($v !~ /("+)\s*$/ or not length($1) & 1) {
62
64
  if (@toks) {
63
- $v .= ',' . shift @toks;
65
+ $v .= $delim . shift @toks;
64
66
  } else {
65
67
  # read another line from the file
66
68
  $raf->ReadLine($buff) or last;
67
- @toks = split ',', $buff;
69
+ @toks = split /\Q$delim/, $buff;
68
70
  last unless @toks;
69
71
  $v .= shift @toks;
70
72
  }
@@ -330,9 +332,10 @@ Read CSV or JSON file into a database hash.
330
332
  2) Optional string used to represent an undefined (missing) tag value.
331
333
  (Used for deleting tags.)
332
334
 
333
- 3) [ReadJSON only] Optional character set for converting Unicode escape
334
- sequences in strings. Defaults to "UTF8". See the ExifTool Charset option
335
- for a list of valid settings.
335
+ 3) For ReadCSV this gives the delimiter for CSV entries, with a default of
336
+ ",". For ReadJSON this is the character set for converting Unicode escape
337
+ sequences in strings, with a default of "UTF8". See the ExifTool Charset
338
+ option for a list of valid character sets.
336
339
 
337
340
  =item Return Value:
338
341