exiftool_vendored 12.62.0 → 12.64.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +50 -1
  3. data/bin/MANIFEST +4 -0
  4. data/bin/META.json +4 -1
  5. data/bin/META.yml +4 -1
  6. data/bin/Makefile.PL +7 -1
  7. data/bin/README +50 -46
  8. data/bin/config_files/guano.config +161 -0
  9. data/bin/exiftool +88 -62
  10. data/bin/lib/Image/ExifTool/7Z.pm +793 -0
  11. data/bin/lib/Image/ExifTool/Apple.pm +6 -3
  12. data/bin/lib/Image/ExifTool/Canon.pm +1 -0
  13. data/bin/lib/Image/ExifTool/CanonRaw.pm +4 -4
  14. data/bin/lib/Image/ExifTool/CanonVRD.pm +4 -1
  15. data/bin/lib/Image/ExifTool/Exif.pm +31 -14
  16. data/bin/lib/Image/ExifTool/FujiFilm.pm +3 -3
  17. data/bin/lib/Image/ExifTool/GPS.pm +5 -2
  18. data/bin/lib/Image/ExifTool/Geotag.pm +4 -1
  19. data/bin/lib/Image/ExifTool/Jpeg2000.pm +226 -28
  20. data/bin/lib/Image/ExifTool/Lang/fr.pm +1467 -202
  21. data/bin/lib/Image/ExifTool/MPF.pm +2 -1
  22. data/bin/lib/Image/ExifTool/Matroska.pm +16 -1
  23. data/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -2
  24. data/bin/lib/Image/ExifTool/Nikon.pm +419 -5
  25. data/bin/lib/Image/ExifTool/NikonCustom.pm +13 -3
  26. data/bin/lib/Image/ExifTool/PDF.pm +9 -1
  27. data/bin/lib/Image/ExifTool/PLIST.pm +8 -1
  28. data/bin/lib/Image/ExifTool/PNG.pm +6 -6
  29. data/bin/lib/Image/ExifTool/PhaseOne.pm +5 -5
  30. data/bin/lib/Image/ExifTool/QuickTime.pm +74 -21
  31. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +20 -19
  32. data/bin/lib/Image/ExifTool/README +2 -2
  33. data/bin/lib/Image/ExifTool/RIFF.pm +11 -9
  34. data/bin/lib/Image/ExifTool/Shortcuts.pm +2 -1
  35. data/bin/lib/Image/ExifTool/SigmaRaw.pm +4 -4
  36. data/bin/lib/Image/ExifTool/Sony.pm +103 -8
  37. data/bin/lib/Image/ExifTool/TagLookup.pm +4738 -4630
  38. data/bin/lib/Image/ExifTool/TagNames.pod +249 -5
  39. data/bin/lib/Image/ExifTool/Validate.pm +17 -1
  40. data/bin/lib/Image/ExifTool/WriteExif.pl +9 -7
  41. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +21 -9
  42. data/bin/lib/Image/ExifTool/WriteXMP.pl +2 -2
  43. data/bin/lib/Image/ExifTool/Writer.pl +28 -10
  44. data/bin/lib/Image/ExifTool/XMP.pm +14 -2
  45. data/bin/lib/Image/ExifTool/XMP2.pl +32 -0
  46. data/bin/lib/Image/ExifTool/XMPStruct.pl +96 -28
  47. data/bin/lib/Image/ExifTool/ZIP.pm +5 -5
  48. data/bin/lib/Image/ExifTool.pm +67 -39
  49. data/bin/lib/Image/ExifTool.pod +83 -52
  50. data/bin/perl-Image-ExifTool.spec +44 -44
  51. data/lib/exiftool_vendored/version.rb +1 -1
  52. metadata +4 -2
@@ -16,7 +16,7 @@ use strict;
16
16
  use vars qw($VERSION);
17
17
  use Image::ExifTool qw(:DataAccess :Utils);
18
18
 
19
- $VERSION = '1.34';
19
+ $VERSION = '1.36';
20
20
 
21
21
  sub ProcessJpeg2000Box($$$);
22
22
  sub ProcessJUMD($$$);
@@ -130,7 +130,10 @@ my %j2cMarker = (
130
130
  NOTES => q{
131
131
  The tags below are found in JPEG 2000 images and the JUMBF metadata in JPEG
132
132
  images, but not all of these are extracted. Note that ExifTool currently
133
- writes only EXIF, IPTC and XMP tags in Jpeg2000 images.
133
+ writes only EXIF, IPTC and XMP tags in Jpeg2000 images, and EXIF and XMP in
134
+ JXL images. ExifTool will read/write Brotli-compressed EXIF and XMP in JXL
135
+ images, but the API L<Compress|../ExifTool.html#Compress> option must be set to create new EXIF and XMP
136
+ in compressed format.
134
137
  },
135
138
  #
136
139
  # NOTE: ONLY TAGS WITH "Format" DEFINED ARE EXTRACTED!
@@ -262,7 +265,7 @@ my %j2cMarker = (
262
265
  uuid => [
263
266
  {
264
267
  Name => 'UUID-EXIF',
265
- # (this is the EXIF that we create)
268
+ # (this is the EXIF that we create in JP2)
266
269
  Condition => '$$valPt=~/^JpgTiffExif->JP2(?!Exif\0\0)/',
267
270
  SubDirectory => {
268
271
  TagTable => 'Image::ExifTool::Exif::Main',
@@ -298,7 +301,7 @@ my %j2cMarker = (
298
301
  },
299
302
  {
300
303
  Name => 'UUID-IPTC',
301
- # (this is the IPTC that we create)
304
+ # (this is the IPTC that we create in JP2)
302
305
  Condition => '$$valPt=~/^\x33\xc7\xa4\xd2\xb8\x1d\x47\x23\xa0\xba\xf1\xa3\xe0\x97\xad\x38/',
303
306
  SubDirectory => {
304
307
  TagTable => 'Image::ExifTool::IPTC::Main',
@@ -431,7 +434,6 @@ my %j2cMarker = (
431
434
  # stuff seen in JPEG XL images:
432
435
  #
433
436
  # jbrd - JPEG Bitstream Reconstruction Data (allows lossless conversion back to original JPG)
434
- # jxlp - partial JXL codestream
435
437
  jxlc => {
436
438
  Name => 'JXLCodestream',
437
439
  Format => 'undef',
@@ -441,6 +443,15 @@ my %j2cMarker = (
441
443
  },
442
444
  RawConv => 'Image::ExifTool::Jpeg2000::ProcessJXLCodestream($self,\$val); undef',
443
445
  },
446
+ jxlp => {
447
+ Name => 'PartialJXLCodestream',
448
+ Format => 'undef',
449
+ Notes => q{
450
+ Partial codestreams in JPEG XL image. Currently processed only to determine
451
+ ImageSize
452
+ },
453
+ RawConv => 'Image::ExifTool::Jpeg2000::ProcessJXLCodestream($self,\$val); undef',
454
+ },
444
455
  Exif => {
445
456
  Name => 'EXIF',
446
457
  SubDirectory => {
@@ -451,6 +462,38 @@ my %j2cMarker = (
451
462
  Start => '$valuePtr + 4 + (length($$dataPt)-$valuePtr > 4 ? unpack("N", $$dataPt) : 0)',
452
463
  },
453
464
  },
465
+ hrgm => {
466
+ Name => 'GainMapImage',
467
+ Groups => { 2 => 'Preview' },
468
+ Format => 'undef',
469
+ Binary => 1,
470
+ },
471
+ brob => [{ # Brotli-encoded metadata (see https://libjxl.readthedocs.io/en/latest/api_decoder.html)
472
+ Name => 'BrotliXMP',
473
+ Condition => '$$valPt =~ /^xml /i',
474
+ SubDirectory => {
475
+ TagTable => 'Image::ExifTool::XMP::Main',
476
+ ProcessProc => \&ProcessBrotli,
477
+ WriteProc => \&ProcessBrotli,
478
+ # (don't set DirName to 'XMP' because this would enable a block write of raw XMP)
479
+ },
480
+ },{
481
+ Name => 'BrotliEXIF',
482
+ Condition => '$$valPt =~ /^exif/i',
483
+ SubDirectory => {
484
+ TagTable => 'Image::ExifTool::Exif::Main',
485
+ ProcessProc => \&ProcessBrotli,
486
+ WriteProc => \&ProcessBrotli,
487
+ # (don't set DirName to 'EXIF' because this would enable a block write of raw EXIF)
488
+ },
489
+ },{
490
+ Name => 'BrotliJUMB',
491
+ Condition => '$$valPt =~ /^jumb/i',
492
+ SubDirectory => {
493
+ TagTable => 'Image::ExifTool::Jpeg2000::Main',
494
+ ProcessProc => \&ProcessBrotli,
495
+ },
496
+ }],
454
497
  );
455
498
 
456
499
  %Image::ExifTool::Jpeg2000::ImageHeader = (
@@ -840,12 +883,31 @@ sub CreateNewBoxes($$)
840
883
  $tagTable = GetTagTable('Image::ExifTool::XMP::Main') if $dir eq 'XMP';
841
884
  my %dirInfo = (
842
885
  DirName => $dir,
843
- Parent => 'JP2',
886
+ Parent => $tag,
844
887
  );
888
+ my $compress = $et->Options('Compress');
889
+ $dirInfo{Compact} = 1 if $$et{IsJXL} and $compress;
845
890
  my $newdir = $et->WriteDirectory(\%dirInfo, $tagTable, $$subdir{WriteProc});
846
891
  if (defined $newdir and length $newdir) {
847
892
  # not sure why, but EXIF box is padded with leading 0's in my sample
848
893
  my $pad = $dirName eq 'Exif' ? "\0\0\0\0" : '';
894
+ if ($$et{IsJXL} and $compress) {
895
+ # create as Brotli-compressed metadata
896
+ if (eval { require IO::Compress::Brotli }) {
897
+ my $compressed;
898
+ eval { $compressed = IO::Compress::Brotli::bro($pad . $newdir) };
899
+ if ($@ or not $compressed) {
900
+ $et->Warn("Error encoding $dirName brob box");
901
+ } else {
902
+ $et->VPrint(0, " Writing Brotli-compressed $dir\n");
903
+ $newdir = $compressed;
904
+ $pad = $tag;
905
+ $tag = 'brob';
906
+ }
907
+ } else {
908
+ $et->WarnOnce('Install IO::Compress::Brotli to create Brotli-compressed metadata');
909
+ }
910
+ }
849
911
  my $boxhdr = pack('N', length($newdir) + length($pad) + 8) . $tag;
850
912
  Write($outfile, $boxhdr, $pad, $newdir) or return 0;
851
913
  next;
@@ -934,7 +996,7 @@ sub ProcessJpeg2000Box($$$)
934
996
  my $raf = $$dirInfo{RAF};
935
997
  my $outfile = $$dirInfo{OutFile};
936
998
  my $dirEnd = $dirStart + $dirLen;
937
- my ($err, $outBuff, $verbose, $doColour, $md5);
999
+ my ($err, $outBuff, $verbose, $doColour, $hash);
938
1000
 
939
1001
  if ($outfile) {
940
1002
  unless ($raf) {
@@ -952,8 +1014,8 @@ sub ProcessJpeg2000Box($$$)
952
1014
  # (must not set verbose flag when writing!)
953
1015
  $verbose = $$et{OPTIONS}{Verbose};
954
1016
  $et->VerboseDir($$dirInfo{DirName}) if $verbose;
955
- # do MD5 if requested, but only for top-level image data
956
- $md5 = $$et{ImageDataMD5} if $raf;
1017
+ # do hash if requested, but only for top-level image data
1018
+ $hash = $$et{ImageDataHash} if $raf;
957
1019
  }
958
1020
  # loop through all contained boxes
959
1021
  my ($pos, $boxLen, $lastBox);
@@ -1023,8 +1085,8 @@ sub ProcessJpeg2000Box($$$)
1023
1085
  my $msg = sprintf("offset 0x%.4x to end of file", $dataPos + $base + $pos);
1024
1086
  $et->VPrint(0, "$$et{INDENT}- Tag '${boxID}' ($msg)\n");
1025
1087
  }
1026
- if ($md5 and $isImageData{$boxID}) {
1027
- $et->ImageDataMD5($raf, undef, $boxID);
1088
+ if ($hash and $isImageData{$boxID}) {
1089
+ $et->ImageDataHash($raf, undef, $boxID);
1028
1090
  }
1029
1091
  }
1030
1092
  last; # (ignore the rest of the file when reading)
@@ -1042,8 +1104,8 @@ sub ProcessJpeg2000Box($$$)
1042
1104
  Write($outfile, $$dataPt) or $err = 1;
1043
1105
  $raf->Read($buff,$boxLen) == $boxLen or $err = '', last;
1044
1106
  Write($outfile, $buff) or $err = 1;
1045
- } elsif ($md5 and $isImageData{$boxID}) {
1046
- $et->ImageDataMD5($raf, $boxLen, $boxID);
1107
+ } elsif ($hash and $isImageData{$boxID}) {
1108
+ $et->ImageDataHash($raf, $boxLen, $boxID);
1047
1109
  } else {
1048
1110
  $raf->Seek($boxLen, 1) or $err = 'Seek error', last;
1049
1111
  }
@@ -1056,9 +1118,9 @@ sub ProcessJpeg2000Box($$$)
1056
1118
  # read the box data
1057
1119
  $dataPos = $raf->Tell() - $base;
1058
1120
  $raf->Read($buff,$boxLen) == $boxLen or $err = '', last;
1059
- if ($md5 and $isImageData{$boxID}) {
1060
- $md5->add($buff);
1061
- $et->VPrint(0, "$$et{INDENT}(ImageDataMD5: $boxLen bytes of $boxID data)\n");
1121
+ if ($hash and $isImageData{$boxID}) {
1122
+ $hash->add($buff);
1123
+ $et->VPrint(0, "$$et{INDENT}(ImageDataHash: $boxLen bytes of $boxID data)\n");
1062
1124
  }
1063
1125
  $valuePtr = 0;
1064
1126
  $dataLen = $boxLen;
@@ -1144,19 +1206,66 @@ sub ProcessJpeg2000Box($$$)
1144
1206
  $subdirInfo{DirName} =~ s/^UUID-//;
1145
1207
  my $subTable = GetTagTable($$subdir{TagTable}) || $tagTablePtr;
1146
1208
  if ($outfile) {
1147
- # remove this directory from our create list
1148
- delete $$et{AddJp2Dirs}{$$tagInfo{Name}}; # (eg. 'EXIF' or 'XMP')
1149
- delete $$et{AddJp2Dirs}{$boxID}; # (eg. 'Exif' or 'xml ')
1209
+ # (special case for brob box, which may be EXIF or XMP)
1210
+ my $fakeID = $boxID;
1211
+ if ($boxID eq 'brob') {
1212
+ # I have seen 'brob' ID's with funny cases, so standardize these
1213
+ $fakeID = 'xml ' if $$dataPt =~ /^xml /i;
1214
+ $fakeID = 'Exif' if $$dataPt =~ /^Exif/i;
1215
+ }
1150
1216
  my $newdir;
1151
1217
  # only edit writable UUID, Exif and jp2h boxes
1152
- if ($uuid or $boxID eq 'Exif' or ($boxID eq 'xml ' and $$et{IsJXL}) or
1218
+ if ($uuid or $fakeID eq 'Exif' or ($fakeID eq 'xml ' and $$et{IsJXL}) or
1153
1219
  ($boxID eq 'jp2h' and $$et{EDIT_DIRS}{jp2h}))
1154
1220
  {
1221
+ my $compress = $et->Options('Compress');
1222
+ $subdirInfo{Parent} = $fakeID;
1223
+ $subdirInfo{Compact} = 1 if $compress and $$et{IsJXL};
1155
1224
  $newdir = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc});
1156
1225
  next if defined $newdir and not length $newdir; # next if deleting the box
1226
+ # compress JXL EXIF or XMP metadata if requested
1227
+ if (defined $newdir and $$et{IsJXL} and defined $compress and
1228
+ ($fakeID eq 'Exif' or $fakeID eq 'xml '))
1229
+ {
1230
+ if ($compress and $boxID ne 'brob') {
1231
+ # rewrite as a Brotli-compressed 'brob' box
1232
+ if (eval { require IO::Compress::Brotli }) {
1233
+ my $pad = $boxID eq 'Exif' ? "\0\0\0\0" : '';
1234
+ my $compressed;
1235
+ eval { $compressed = IO::Compress::Brotli::bro($pad . $newdir) };
1236
+ if ($@ or not $compressed) {
1237
+ $et->Warn("Error encoding $boxID brob box");
1238
+ } else {
1239
+ $et->VPrint(0, " Writing Brotli-compressed $boxID\n");
1240
+ $newdir = $boxID . $compressed;
1241
+ $boxID = 'brob';
1242
+ $subdirStart = $valuePtr = 0;
1243
+ ++$$et{CHANGED};
1244
+ }
1245
+ } else {
1246
+ $et->WarnOnce('Install IO::Compress::Brotli to write Brotli-compressed metadata');
1247
+ }
1248
+ } elsif (not $compress and $boxID eq 'brob') {
1249
+ # (in this case, ProcessBrotli has returned uncompressed data,
1250
+ # so change to the uncompressed 'xml ' or 'Exif' box type)
1251
+ $et->VPrint(0, " Writing uncompressed $fakeID\n");
1252
+ $boxID = $fakeID;
1253
+ $subdirStart = $valuePtr = 0;
1254
+ ++$$et{CHANGED};
1255
+ }
1256
+ }
1157
1257
  } elsif (defined $uuid) {
1158
1258
  $et->Warn("Not editing $$tagInfo{Name} box", 1);
1159
1259
  }
1260
+ # remove this directory from our create list
1261
+ delete $$et{AddJp2Dirs}{$fakeID}; # (eg. 'Exif' or 'xml ')
1262
+ if ($boxID eq 'brob') {
1263
+ # (can't make tag Name 'XMP' or 'Exif' for Brotli-compressed tags because it
1264
+ # would break the logic in WriteDirectory(), so we do a lookup here instead)
1265
+ delete $$et{AddJp2Dirs}{{'xml '=>'XMP','Exif'=>'EXIF'}->{$fakeID}};
1266
+ } else {
1267
+ delete $$et{AddJp2Dirs}{$$tagInfo{Name}}; # (eg. 'EXIF' or 'XMP')
1268
+ }
1160
1269
  # use old box data if not changed
1161
1270
  defined $newdir or $newdir = substr($$dataPt, $subdirStart, $subdirLen);
1162
1271
  my $prefixLen = $subdirStart - $valuePtr;
@@ -1232,19 +1341,108 @@ sub GetBits($$)
1232
1341
  return $v;
1233
1342
  }
1234
1343
 
1344
+ #------------------------------------------------------------------------------
1345
+ # Read/write Brotli-encoded metadata
1346
+ # Inputs: 0) ExifTool ref, 1) dirInfoRef, 2) tag table ref
1347
+ # Returns: 1 on success when reading, or new data when writing (undef if unchanged)
1348
+ # (ref https://libjxl.readthedocs.io/en/latest/api_decoder.html)
1349
+ sub ProcessBrotli($$$)
1350
+ {
1351
+ my ($et, $dirInfo, $tagTablePtr) = @_;
1352
+ my $dataPt = $$dirInfo{DataPt};
1353
+
1354
+ return 0 unless length($$dataPt) > 4;
1355
+
1356
+ my $isWriting = $$dirInfo{IsWriting};
1357
+ my $type = substr($$dataPt, 0, 4);
1358
+ $et->VerboseDir("Decrypted Brotli '${type}'") unless $isWriting;
1359
+ my %knownType = ( exif => 'Exif', 'xml ' => 'xml ', jumb => 'jumb' );
1360
+ my $stdType = $knownType{lc $type};
1361
+ unless ($stdType) {
1362
+ $et->Warn('Unknown Brotli box type', 1);
1363
+ return 1;
1364
+ }
1365
+ if ($type ne $stdType) {
1366
+ $et->Warn("Incorrect case for Brotli '${type}' data (should be '${stdType}')");
1367
+ $type = $stdType;
1368
+ }
1369
+ if (eval { require IO::Uncompress::Brotli }) {
1370
+ if ($isWriting and not eval { require IO::Compress::Brotli }) {
1371
+ $et->WarnOnce('Install IO::Compress::Brotli to write Brotli-compressed metadata');
1372
+ return undef;
1373
+ }
1374
+ my $compress = $et->Options('Compress');
1375
+ my $verbose = $isWriting ? 0 : $et->Options('Verbose');
1376
+ my $dat = substr($$dataPt, 4);
1377
+ eval { $dat = IO::Uncompress::Brotli::unbro($dat, 100000000) };
1378
+ $@ and $et->Warn("Error decoding $type brob box"), return 1;
1379
+ $verbose > 2 and $et->VerboseDump(\$dat, Prefix => $$et{INDENT} . ' ');
1380
+ my %dirInfo = ( DataPt => \$dat );
1381
+ if ($type eq 'xml ') {
1382
+ $dirInfo{DirName} = 'XMP'; # (necessary for block read/write)
1383
+ require Image::ExifTool::XMP;
1384
+ if ($isWriting) {
1385
+ $dirInfo{Compact} = 1 if $compress; # (no need to add padding if writing compressed)
1386
+ $dat = $et->WriteDirectory(\%dirInfo, $tagTablePtr);
1387
+ } else {
1388
+ Image::ExifTool::XMP::ProcessXMP($et, \%dirInfo, $tagTablePtr);
1389
+ }
1390
+ } elsif ($type eq 'Exif') {
1391
+ $dirInfo{DirName} = 'EXIF'; # (necessary for block read/write)
1392
+ $dirInfo{DirStart} = 4 + (length($dat) > 4 ? unpack("N", $dat) : 0);
1393
+ if ($dirInfo{DirStart} > length $dat) {
1394
+ $et->Warn("Corrupted Brotli '${type}' data");
1395
+ } elsif ($isWriting) {
1396
+ $dat = $et->WriteDirectory(\%dirInfo, $tagTablePtr, \&Image::ExifTool::WriteTIFF);
1397
+ # add back header word
1398
+ $dat = "\0\0\0\0" . $dat if defined $dat and length $dat;
1399
+ } else {
1400
+ $et->ProcessTIFF(\%dirInfo, $tagTablePtr);
1401
+ }
1402
+ } elsif ($type eq 'jumb') {
1403
+ return undef if $isWriting; # (can't yet write JUMBF)
1404
+ Image::ExifTool::ProcessJUMB($et, \%dirInfo, $tagTablePtr); # (untested)
1405
+ }
1406
+ if ($isWriting) {
1407
+ return undef unless defined $dat;
1408
+ # rewrite as uncompressed if Compress option is set to 0 (or '')
1409
+ return $dat if defined $compress and not $compress;
1410
+ eval { $dat = IO::Compress::Brotli::bro($dat) };
1411
+ $@ and $et->Warn("Error encoding $type brob box"), return undef;
1412
+ $et->VPrint(0, " Writing Brotli-compressed $type\n");
1413
+ return $type . $dat;
1414
+ }
1415
+ } else {
1416
+ $et->WarnOnce('Install IO::Uncompress::Brotli to decode Brotli-compressed metadata');
1417
+ return undef if $isWriting;
1418
+ }
1419
+ return 1;
1420
+ }
1421
+
1235
1422
  #------------------------------------------------------------------------------
1236
1423
  # Extract parameters from JPEG XL codestream [unverified!]
1237
1424
  # Inputs: 0) ExifTool ref, 1) codestream ref
1238
- # Returns: 1
1425
+ # Returns: 1 on success
1239
1426
  sub ProcessJXLCodestream($$)
1240
1427
  {
1241
1428
  my ($et, $dataPt) = @_;
1242
- # add padding if necessary to avoid unpacking past end of data
1243
- if (length $$dataPt < 14) {
1244
- my $tmp = $$dataPt . ("\0" x 14);
1245
- $dataPt = \$tmp;
1429
+
1430
+ return 0 unless $$dataPt =~ /^(\0\0\0\0)?\xff\x0a/; # validate codestream
1431
+ # ignore if already extracted (ie. subsequent jxlp boxes)
1432
+ return 0 if $$et{ProcessedJXLCodestream};
1433
+ $$et{ProcessedJXLCodestream} = 1;
1434
+ # work with first 64 bytes of codestream data
1435
+ # (and add padding if necessary to avoid unpacking past end of data)
1436
+ my $dat;
1437
+ if (length $$dataPt > 64) {
1438
+ $dat = substr($$dataPt, 0, 64);
1439
+ } elsif (length $$dataPt < 18) {
1440
+ $dat = $$dataPt . ("\0" x 18); # (so we'll have a minimum 14 bytes to work with)
1441
+ } else {
1442
+ $dat = $$dataPt;
1246
1443
  }
1247
- my @a = unpack 'x2C12', $$dataPt;
1444
+ $dat =~ s/^\0\0\0\0//; # remove jxlp header word
1445
+ my @a = unpack 'x2C12', $dat;
1248
1446
  my ($x, $y);
1249
1447
  my $small = GetBits(\@a, 1);
1250
1448
  if ($small) {
@@ -1362,8 +1560,8 @@ sub ProcessJXL($$)
1362
1560
  $$dirInfo{RAF} = new File::RandomAccess(\$buff);
1363
1561
  } else {
1364
1562
  $et->SetFileType('JXL Codestream','image/jxl', 'jxl');
1365
- if ($$et{ImageDataMD5} and $raf->Seek(0,0)) {
1366
- $et->ImageDataMD5($raf, undef, 'JXL');
1563
+ if ($$et{ImageDataHash} and $raf->Seek(0,0)) {
1564
+ $et->ImageDataHash($raf, undef, 'JXL');
1367
1565
  }
1368
1566
  return ProcessJXLCodestream($et, \$hdr);
1369
1567
  }