exiftool_vendored 12.58.0 → 12.59.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -36,7 +36,7 @@ use strict;
36
36
  use vars qw($VERSION $AUTOLOAD %stdCase);
37
37
  use Image::ExifTool qw(:DataAccess :Utils);
38
38
 
39
- $VERSION = '1.62';
39
+ $VERSION = '1.63';
40
40
 
41
41
  sub ProcessPNG_tEXt($$$);
42
42
  sub ProcessPNG_iTXt($$$);
@@ -1374,6 +1374,7 @@ sub ProcessPNG($$)
1374
1374
  my $datCount = 0;
1375
1375
  my $datBytes = 0;
1376
1376
  my $fastScan = $et->Options('FastScan');
1377
+ my $md5 = $$et{ImageDataMD5};
1377
1378
  my ($n, $sig, $err, $hbuf, $dbuf, $cbuf);
1378
1379
  my ($wasHdr, $wasEnd, $wasDat, $doTxt, @txtOffset);
1379
1380
 
@@ -1453,6 +1454,7 @@ sub ProcessPNG($$)
1453
1454
  if ($datCount and $chunk ne $datChunk) {
1454
1455
  my $s = $datCount > 1 ? 's' : '';
1455
1456
  print $out "$fileType $datChunk ($datCount chunk$s, total $datBytes bytes)\n";
1457
+ print $out "$$et{INDENT}(ImageDataMD5: $datBytes bytes of $datChunk data)\n" if $md5;
1456
1458
  $datCount = $datBytes = 0;
1457
1459
  }
1458
1460
  }
@@ -1539,7 +1541,17 @@ sub ProcessPNG($$)
1539
1541
  }
1540
1542
  # skip over data chunks if possible/necessary
1541
1543
  } elsif (not $validate or $len > $chunkSizeLimit) {
1542
- $raf->Seek($len + 4, 1) or $et->Warn('Seek error'), last;
1544
+ if ($md5) {
1545
+ while ($len) {
1546
+ my $n = $len > 65536 ? 65536 : $len;
1547
+ $raf->Read($dbuf,$n) == $n or last;
1548
+ $md5->add($dbuf);
1549
+ $len -= $n;
1550
+ }
1551
+ $raf->Read($cbuf, 4) == 4 or $et->Warn('Truncated data'), last;
1552
+ } else {
1553
+ $raf->Seek($len + 4, 1) or $et->Warn('Seek error'), last;
1554
+ }
1543
1555
  next;
1544
1556
  }
1545
1557
  } elsif ($wasDat and $isTxtChunk{$chunk}) {
@@ -1558,6 +1570,7 @@ sub ProcessPNG($$)
1558
1570
  $et->Warn("Corrupted $fileType image") unless $wasEnd;
1559
1571
  last;
1560
1572
  }
1573
+ $md5->add($dbuf) if $md5 and $datChunk; # add to MD5 if necessary
1561
1574
  if ($verbose or $validate or ($outfile and not $fastScan)) {
1562
1575
  # check CRC when in verbose mode (since we don't care about speed)
1563
1576
  my $crc = CalculateCRC(\$hbuf, undef, 4);
@@ -21,7 +21,7 @@ use vars qw($VERSION);
21
21
  use Image::ExifTool qw(:DataAccess :Utils);
22
22
  use Image::ExifTool::Exif;
23
23
 
24
- $VERSION = '1.27';
24
+ $VERSION = '1.28';
25
25
 
26
26
  sub ProcessJpgFromRaw($$$);
27
27
  sub WriteJpgFromRaw($$$);
@@ -266,6 +266,7 @@ my %panasonicWhiteBalance = ( #forum9396
266
266
  PanasonicHack => 1,
267
267
  OffsetPair => 0x117, # (use StripByteCounts as the offset pair)
268
268
  NotRealPair => 1, # (to avoid Validate warning)
269
+ IsImageData => 1,
269
270
  },
270
271
  0x119 => {
271
272
  Name => 'DistortionInfo',
@@ -296,6 +297,20 @@ my %panasonicWhiteBalance = ( #forum9396
296
297
  },
297
298
  },
298
299
  # 0x122 - int32u: RAWDataOffset for the GH5s/GX9, or pointer to end of raw data for G9 (forum9295)
300
+ 0x127 => { #github193 (newer models)
301
+ Name => 'JpgFromRaw2',
302
+ Groups => { 2 => 'Preview' },
303
+ DataTag => 'JpgFromRaw2',
304
+ RawConv => '$self->ValidateImage(\$val,$tag)',
305
+ },
306
+ 0x13b => {
307
+ Name => 'Artist',
308
+ Groups => { 2 => 'Author' },
309
+ Permanent => 1, # (so we don't add it if the model doesn't write it)
310
+ Writable => 'string',
311
+ WriteGroup => 'IFD0',
312
+ RawConv => '$val =~ s/\s+$//; $val', # trim trailing blanks
313
+ },
299
314
  0x2bc => { # PH Extension!!
300
315
  Name => 'ApplicationNotes', # (writable directory!)
301
316
  Writable => 'int8u',
@@ -318,6 +333,17 @@ my %panasonicWhiteBalance = ( #forum9396
318
333
  noise-reduction strengths the R, G and B channels
319
334
  },
320
335
  },
336
+ 0x8298 => { #github193
337
+ Name => 'Copyright',
338
+ Groups => { 2 => 'Author' },
339
+ Permanent => 1, # (so we don't add it if the model doesn't write it)
340
+ Format => 'undef',
341
+ Writable => 'string',
342
+ WriteGroup => 'IFD0',
343
+ RawConv => $Image::ExifTool::Exif::Main{0x8298}{RawConv},
344
+ RawConvInv => $Image::ExifTool::Exif::Main{0x8298}{RawConvInv},
345
+ PrintConvInv => $Image::ExifTool::Exif::Main{0x8298}{PrintConvInv},
346
+ },
321
347
  0x83bb => { # PH Extension!!
322
348
  Name => 'IPTC-NAA', # (writable directory!)
323
349
  Format => 'undef', # convert binary values as undef
@@ -15,7 +15,7 @@ use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
  use Image::ExifTool::Exif;
17
17
 
18
- $VERSION = '1.07';
18
+ $VERSION = '1.08';
19
19
 
20
20
  sub WritePhaseOne($$$);
21
21
  sub ProcessPhaseOne($$$);
@@ -84,6 +84,7 @@ my @formatName = ( undef, 'string', 'int16s', undef, 'int32s' );
84
84
  Name => 'RawData',
85
85
  Format => 'undef', # (actually 2-byte integers, but don't convert)
86
86
  Binary => 1,
87
+ IsImageData => 1,
87
88
  PutFirst => 1,
88
89
  Writable => 0,
89
90
  Drop => 1, # don't copy to other file types
@@ -584,6 +585,7 @@ sub ProcessPhaseOne($$$)
584
585
  my $dirLen = $$dirInfo{DirLen} || $$dirInfo{DataLen} - $dirStart;
585
586
  my $binary = $et->Options('Binary');
586
587
  my $verbose = $et->Options('Verbose');
588
+ my $md5 = $$et{ImageDataMD5};
587
589
  my $htmlDump = $$et{HTML_DUMP};
588
590
 
589
591
  return 0 if $dirLen < 12;
@@ -676,6 +678,17 @@ sub ProcessPhaseOne($$$)
676
678
  }
677
679
  }
678
680
  }
681
+ if ($md5 and $tagInfo and $$tagInfo{IsImageData}) {
682
+ my ($pos, $len) = ($valuePtr, $size);
683
+ while ($len) {
684
+ my $n = $len > 65536 ? 65536 : $len;
685
+ my $tmp = substr($$dataPt, $pos, $n);
686
+ $md5->add($tmp);
687
+ $len -= $n;
688
+ $pos += $n;
689
+ }
690
+ $et->VPrint(0, "$$et{INDENT}(ImageDataMD5: $size bytes of PhaseOne:$$tagInfo{Name})\n");
691
+ }
679
692
  my %parms = (
680
693
  DirName => $ifdType,
681
694
  Index => $index,
@@ -447,15 +447,16 @@ my %dupDirOK = ( ipco => 1, '----' => 1 );
447
447
  my %eeStd = ( stco => 'stbl', co64 => 'stbl', stsz => 'stbl', stz2 => 'stbl',
448
448
  stsc => 'stbl', stts => 'stbl' );
449
449
 
450
+ # atoms required for generating ImageDataMD5
451
+ my %md5Box = ( vide => { %eeStd }, soun => { %eeStd } );
452
+
450
453
  # boxes and their containers for the various handler types that we want to save
451
454
  # when the ExtractEmbedded is enabled (currently only the 'gps ' container name is
452
455
  # used, but others have been checked against all available sample files and may be
453
456
  # useful in the future if the names are used for different boxes on other locations)
454
457
  my %eeBox = (
455
458
  # (note: vide is only processed if specific atoms exist in the VideoSampleDesc)
456
- vide => { %eeStd,
457
- JPEG => 'stsd',
458
- },
459
+ vide => { %eeStd, JPEG => 'stsd' },
459
460
  text => { %eeStd },
460
461
  meta => { %eeStd },
461
462
  sbtl => { %eeStd },
@@ -9285,7 +9286,8 @@ sub ProcessMOV($$;$)
9285
9286
  $$raf{NoBuffer} = 1 if $fast; # disable buffering in FastScan mode
9286
9287
 
9287
9288
  my $ee = $$et{OPTIONS}{ExtractEmbedded};
9288
- if ($ee) {
9289
+ my $md5 = $$et{ImageDataMD5};
9290
+ if ($ee or $md5) {
9289
9291
  $unkOpt = $$et{OPTIONS}{Unknown};
9290
9292
  require 'Image/ExifTool/QuickTimeStream.pl';
9291
9293
  }
@@ -9367,7 +9369,7 @@ sub ProcessMOV($$;$)
9367
9369
  # set flag to store additional information for ExtractEmbedded option
9368
9370
  my $handlerType = $$et{HandlerType};
9369
9371
  if ($eeBox{$handlerType} and $eeBox{$handlerType}{$tag}) {
9370
- if ($ee) {
9372
+ if ($ee or $md5) {
9371
9373
  # (there is another 'gps ' box with a track log that doesn't contain offsets)
9372
9374
  if ($tag ne 'gps ' or $eeBox{$handlerType}{$tag} eq $dirID) {
9373
9375
  $eeTag = 1;
@@ -9379,6 +9381,9 @@ sub ProcessMOV($$;$)
9379
9381
  } elsif ($ee and $ee > 1 and $eeBox2{$handlerType} and $eeBox2{$handlerType}{$tag}) {
9380
9382
  $eeTag = 1;
9381
9383
  $$et{OPTIONS}{Unknown} = 1;
9384
+ } elsif ($md5 and $md5Box{$handlerType} and $md5Box{$handlerType}{$tag}) {
9385
+ $eeTag = 1;
9386
+ $$et{OPTIONS}{Unknown} = 1;
9382
9387
  }
9383
9388
  my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
9384
9389
 
@@ -9611,7 +9616,7 @@ ItemID: foreach $id (keys %$items) {
9611
9616
  }
9612
9617
  if ($tag eq 'stbl') {
9613
9618
  # process sample data when exiting SampleTable box if extracting embedded
9614
- ProcessSamples($et) if $ee;
9619
+ ProcessSamples($et) if $ee or $md5;
9615
9620
  } elsif ($tag eq 'minf') {
9616
9621
  $$et{HandlerType} = ''; # reset handler type at end of media info box
9617
9622
  }
@@ -599,6 +599,8 @@ my %insvLimit = (
599
599
  0x1a => 'Firmware',
600
600
  0x2a => {
601
601
  Name => 'Parameters',
602
+ # (see https://exiftool.org/forum/index.php?msg=78942)
603
+ Notes => 'number of lenses, 6-axis orientation of each lens, raw resolution',
602
604
  ValueConv => '$val =~ tr/_/ /; $val',
603
605
  },
604
606
  );
@@ -1125,23 +1127,37 @@ sub Process_text($$$;$)
1125
1127
  # Inputs: 0) ExifTool ref
1126
1128
  # Notes: Also accesses ExifTool RAF*, SET_GROUP1, HandlerType, MetaFormat,
1127
1129
  # ee*, and avcC elements (* = must exist)
1130
+ # - may be called either due to ExtractEmbedded option, or ImageDataMD5 requested
1131
+ # - MD5 includes only video and audio data
1128
1132
  sub ProcessSamples($)
1129
1133
  {
1130
1134
  my $et = shift;
1131
1135
  my ($raf, $ee) = @$et{qw(RAF ee)};
1132
- my ($i, $buff, $pos, $hdrLen, $hdrFmt, @time, @dur, $oldIndent);
1136
+ my ($i, $buff, $pos, $hdrLen, $hdrFmt, @time, @dur, $oldIndent, $md5);
1133
1137
 
1134
1138
  return unless $ee;
1135
1139
  delete $$et{ee}; # use only once
1136
1140
 
1137
- # only process specific types of video streams
1141
+ my $eeOpt = $et->Options('ExtractEmbedded');
1138
1142
  my $type = $$et{HandlerType} || '';
1139
1143
  if ($type eq 'vide') {
1140
- if ($$ee{avcC}) { $type = 'avcC' }
1141
- elsif ($$ee{JPEG}) { $type = 'JPEG' }
1142
- else { return }
1144
+ # only process specific types of video streams
1145
+ $md5 = $$et{ImageDataMD5};
1146
+ # only process specific video types if ExtractEmbedded was used
1147
+ # (otherwise we are only here to calculate the audio/video MD5)
1148
+ if ($eeOpt) {
1149
+ if ($$ee{avcC}) { $type = 'avcC' }
1150
+ elsif ($$ee{JPEG}) { $type = 'JPEG' }
1151
+ else { return unless $md5 }
1152
+ }
1153
+ } elsif ($type eq 'soun') {
1154
+ $md5 = $$et{ImageDataMD5};
1155
+ return unless $md5;
1156
+ } else {
1157
+ return unless $eeOpt; # (don't do MD5 on other types)
1143
1158
  }
1144
1159
 
1160
+ my $md5size = 0;
1145
1161
  my ($start, $size) = @$ee{qw(start size)};
1146
1162
  #
1147
1163
  # determine sample start offsets from chunk offsets (stco) and sample-to-chunk table (stsc),
@@ -1160,13 +1176,16 @@ sub ProcessSamples($)
1160
1176
  $timeDelta = shift @$stts;
1161
1177
  }
1162
1178
  my $ts = $$et{MediaTS} || 1;
1179
+ my @chunkSize; # total size of each chunk
1163
1180
  foreach $chunkStart (@$stco) {
1164
1181
  if ($iChunk >= $nextChunk and @$stsc) {
1165
1182
  ($startChunk, $samplesPerChunk, $descIdx) = @{shift @$stsc};
1166
1183
  $nextChunk = $$stsc[0][0] if @$stsc;
1167
1184
  }
1168
1185
  @$size < @$start + $samplesPerChunk and $et->WarnOnce('Sample size error'), last;
1186
+ last unless defined $chunkStart and length $chunkStart;
1169
1187
  my $sampleStart = $chunkStart;
1188
+ my $chunkSize = 0;
1170
1189
  Sample: for ($i=0; ; ) {
1171
1190
  push @$start, $sampleStart;
1172
1191
  if (defined $time) {
@@ -1184,12 +1203,19 @@ Sample: for ($i=0; ; ) {
1184
1203
  --$timeCount;
1185
1204
  }
1186
1205
  # (eventually should use the description indices: $descIdx)
1206
+ $chunkSize += $$size[$#$start];
1187
1207
  last if ++$i >= $samplesPerChunk;
1188
1208
  $sampleStart += $$size[$#$start];
1189
1209
  }
1210
+ push @chunkSize, $chunkSize;
1190
1211
  ++$iChunk;
1191
1212
  }
1192
1213
  @$start == @$size or $et->WarnOnce('Incorrect sample start/size count'), return;
1214
+ # process as chunks if we are only interested in calculating MD5
1215
+ if ($type eq 'soun' or $type eq 'vide') {
1216
+ $start = $stco;
1217
+ $size = \@chunkSize;
1218
+ }
1193
1219
  }
1194
1220
  #
1195
1221
  # extract and parse the sample data
@@ -1221,6 +1247,10 @@ Sample: for ($i=0; ; ) {
1221
1247
  my $size = $$size[$i];
1222
1248
  next unless $raf->Seek($$start[$i], 0) and $raf->Read($buff, $size) == $size;
1223
1249
 
1250
+ if ($md5) {
1251
+ $md5->add($buff);
1252
+ $md5size += length $buff;
1253
+ }
1224
1254
  if ($type eq 'avcC') {
1225
1255
  next if length($buff) <= $hdrLen;
1226
1256
  # scan through all NAL units and send them to ParseH264Video()
@@ -1347,6 +1377,8 @@ Sample: for ($i=0; ; ) {
1347
1377
  SetGPSDateTime($et, $tagTbl, $time[$i]) if $$et{FoundGPSLatitude} and not $$et{FoundGPSDateTime};
1348
1378
  }
1349
1379
  if ($verbose) {
1380
+ my $str = $type eq 'soun' ? 'Audio' : 'Video';
1381
+ $et->VPrint(0, "$$et{INDENT}(ImageDataMD5: $md5size bytes of $str data)\n") if $md5size;
1350
1382
  $$et{INDENT} = $oldIndent;
1351
1383
  $et->VPrint(0, "--------------------------\n");
1352
1384
  }
@@ -30,7 +30,7 @@ use strict;
30
30
  use vars qw($VERSION $AUTOLOAD);
31
31
  use Image::ExifTool qw(:DataAccess :Utils);
32
32
 
33
- $VERSION = '1.62';
33
+ $VERSION = '1.63';
34
34
 
35
35
  sub ConvertTimecode($);
36
36
  sub ProcessSGLT($$$);
@@ -38,6 +38,13 @@ sub ProcessSLLT($$$);
38
38
  sub ProcessLucas($$$);
39
39
  sub WriteRIFF($$);
40
40
 
41
+ # RIFF chunks containing image data (to include in ImageDataMD5 digest)
42
+ my %isImageData = (
43
+ LIST_movi => 1, # (AVI: contains ##db, ##dc, ##wb)
44
+ data => 1, # (WAV)
45
+ 'VP8 '=>1, VP8L=>1, ANIM=>1, ANMF=>1, ALPH=>1, # (WebP)
46
+ );
47
+
41
48
  # recognized RIFF variants
42
49
  my %riffType = (
43
50
  'WAVE' => 'WAV', 'AVI ' => 'AVI', 'WEBP' => 'WEBP',
@@ -1980,6 +1987,7 @@ sub ProcessRIFF($$)
1980
1987
  my $unknown = $et->Options('Unknown');
1981
1988
  my $validate = $et->Options('Validate');
1982
1989
  my $ee = $et->Options('ExtractEmbedded');
1990
+ my $md5 = $$et{ImageDataMD5};
1983
1991
 
1984
1992
  # verify this is a valid RIFF file
1985
1993
  return 0 unless $raf->Read($buff, 12) == 12;
@@ -2059,6 +2067,10 @@ sub ProcessRIFF($$)
2059
2067
  # (in LIST_movi chunk: ##db = uncompressed DIB, ##dc = compressed DIB, ##wb = audio data)
2060
2068
  if ($tagInfo or (($verbose or $unknown) and $tag !~ /^(data|idx1|LIST_movi|RIFF|\d{2}(db|dc|wb))$/)) {
2061
2069
  $raf->Read($buff, $len2) == $len2 or $err=1, last;
2070
+ if ($md5 and $isImageData{$tag}) {
2071
+ $md5->add($buff);
2072
+ $et->VPrint(0, "$$et{INDENT}(ImageDataMD5: '${tag}' chunk, $len2 bytes)\n");
2073
+ }
2062
2074
  my $setGroups;
2063
2075
  if ($tagInfo and ref $tagInfo eq 'HASH' and $$tagInfo{SetGroups}) {
2064
2076
  $setGroups = $$et{SET_GROUP0} = $$et{SET_GROUP1} = $$tagInfo{SetGroups};
@@ -2085,18 +2097,34 @@ sub ProcessRIFF($$)
2085
2097
  # extract information from remaining file as an embedded file
2086
2098
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2087
2099
  next; # (must not increment $pos)
2088
- } elsif ($tag eq 'LIST_movi' and $ee) {
2089
- next; # parse into movi chunk
2090
2100
  } else {
2091
- if ($len > 0x7fffffff and not $et->Options('LargeFileSupport')) {
2092
- $et->Warn("Stopped parsing at large $tag chunk (LargeFileSupport not set)");
2093
- last;
2101
+ my $rewind;
2102
+ # do MD5 if required
2103
+ if ($md5 and $isImageData{$tag}) {
2104
+ $rewind = $raf->Tell();
2105
+ my $more = $len2;
2106
+ while ($more) {
2107
+ my $n = $more > 65536 ? 65536 : $more;
2108
+ $raf->Read($buff, $n) == $n or $err = 1, last;
2109
+ $md5->add($buff);
2110
+ $more -= $n;
2111
+ }
2112
+ $et->VPrint(0, "$$et{INDENT}(ImageDataMD5: '${tag}' chunk, $len2 bytes)\n");
2094
2113
  }
2095
- if ($validate and $len2) {
2096
- # (must actually try to read something after seeking to detect error)
2097
- $raf->Seek($len2-1, 1) and $raf->Read($buff, 1) == 1 or $err = 1, last;
2098
- } else {
2099
- $raf->Seek($len2, 1) or $err=1, last;
2114
+ if ($tag eq 'LIST_movi' and $ee) {
2115
+ $raf->Seek($rewind, 0) or $err = 1, last if $rewind;
2116
+ next; # parse into movi chunk
2117
+ } elsif (not $rewind) {
2118
+ if ($len > 0x7fffffff and not $et->Options('LargeFileSupport')) {
2119
+ $et->Warn("Stopped parsing at large $tag chunk (LargeFileSupport not set)");
2120
+ last;
2121
+ }
2122
+ if ($validate and $len2) {
2123
+ # (must actually try to read something after seeking to detect error)
2124
+ $raf->Seek($len2-1, 1) and $raf->Read($buff, 1) == 1 or $err = 1, last;
2125
+ } else {
2126
+ $raf->Seek($len2, 1) or $err=1, last;
2127
+ }
2100
2128
  }
2101
2129
  }
2102
2130
  $pos += $len2;