exiftool-vendored.pl 12.84.0 → 12.89.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.
Files changed (49) hide show
  1. package/bin/Changes +94 -3
  2. package/bin/MANIFEST +1 -0
  3. package/bin/META.json +1 -1
  4. package/bin/META.yml +16 -16
  5. package/bin/README +47 -46
  6. package/bin/build_geolocation +96 -20
  7. package/bin/config_files/example.config +5 -0
  8. package/bin/config_files/onone.config +28 -0
  9. package/bin/exiftool +67 -57
  10. package/bin/lib/Image/ExifTool/AIFF.pm +8 -4
  11. package/bin/lib/Image/ExifTool/ASF.pm +4 -1
  12. package/bin/lib/Image/ExifTool/Apple.pm +2 -1
  13. package/bin/lib/Image/ExifTool/BuildTagLookup.pm +14 -8
  14. package/bin/lib/Image/ExifTool/Canon.pm +100 -7
  15. package/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
  16. package/bin/lib/Image/ExifTool/CanonVRD.pm +5 -2
  17. package/bin/lib/Image/ExifTool/DPX.pm +3 -3
  18. package/bin/lib/Image/ExifTool/FujiFilm.pm +46 -4
  19. package/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
  20. package/bin/lib/Image/ExifTool/Geolocation.pm +18 -8
  21. package/bin/lib/Image/ExifTool/ID3.pm +36 -8
  22. package/bin/lib/Image/ExifTool/InDesign.pm +8 -4
  23. package/bin/lib/Image/ExifTool/Jpeg2000.pm +0 -1
  24. package/bin/lib/Image/ExifTool/Lang/de.pm +2 -2
  25. package/bin/lib/Image/ExifTool/Matroska.pm +66 -10
  26. package/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -2
  27. package/bin/lib/Image/ExifTool/Nikon.pm +21 -2
  28. package/bin/lib/Image/ExifTool/Olympus.pm +27 -17
  29. package/bin/lib/Image/ExifTool/Panasonic.pm +1 -0
  30. package/bin/lib/Image/ExifTool/PanasonicRaw.pm +1 -0
  31. package/bin/lib/Image/ExifTool/Pentax.pm +139 -22
  32. package/bin/lib/Image/ExifTool/QuickTime.pm +70 -16
  33. package/bin/lib/Image/ExifTool/QuickTimeStream.pl +24 -2
  34. package/bin/lib/Image/ExifTool/RIFF.pm +20 -10
  35. package/bin/lib/Image/ExifTool/Samsung.pm +29 -1
  36. package/bin/lib/Image/ExifTool/Sony.pm +21 -11
  37. package/bin/lib/Image/ExifTool/TagLookup.pm +6806 -6782
  38. package/bin/lib/Image/ExifTool/TagNames.pod +124 -34
  39. package/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
  40. package/bin/lib/Image/ExifTool/WriteQuickTime.pl +86 -16
  41. package/bin/lib/Image/ExifTool/Writer.pl +8 -6
  42. package/bin/lib/Image/ExifTool/XMP.pm +10 -8
  43. package/bin/lib/Image/ExifTool/XMP2.pl +51 -30
  44. package/bin/lib/Image/ExifTool/ZIP.pm +8 -4
  45. package/bin/lib/Image/ExifTool.pm +78 -45
  46. package/bin/lib/Image/ExifTool.pod +66 -50
  47. package/bin/perl-Image-ExifTool.spec +45 -45
  48. package/bin/pp_build_exe.args +4 -4
  49. package/package.json +3 -3
@@ -101,8 +101,22 @@ my %sPose = (
101
101
  my %sEarthPose = (
102
102
  STRUCT_NAME => 'EarthPose',
103
103
  NAMESPACE => { EarthPose => 'http://ns.google.com/photos/dd/1.0/earthpose/' },
104
- Latitude => { Writable => 'real', Groups => { 2 => 'Location' }, %latConv },
105
- Longitude => { Writable => 'real', Groups => { 2 => 'Location' }, %longConv },
104
+ Latitude => {
105
+ Writable => 'real',
106
+ Groups => { 2 => 'Location' },
107
+ ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
108
+ ValueConvInv => '$val',
109
+ PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
110
+ PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")',
111
+ },
112
+ Longitude => {
113
+ Writable => 'real',
114
+ Groups => { 2 => 'Location' },
115
+ ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
116
+ ValueConvInv => '$val',
117
+ PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
118
+ PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")',
119
+ },
106
120
  Altitude => {
107
121
  Writable => 'real',
108
122
  Groups => { 2 => 'Location' },
@@ -1921,6 +1935,7 @@ my %sACDSeeRegionStruct = (
1921
1935
  SpecialTypeID => { List => 'Bag' },
1922
1936
  PortraitNote => { },
1923
1937
  DisableAutoCreation => { List => 'Bag' },
1938
+ DisableSuggestedAction => { List => 'Bag' }, #forum16147
1924
1939
  hdrp_makernote => {
1925
1940
  Name => 'HDRPMakerNote',
1926
1941
  # decoded data starts with the following bytes, but nothing yet is known about its contents:
@@ -2109,35 +2124,41 @@ my %sACDSeeRegionStruct = (
2109
2124
  );
2110
2125
 
2111
2126
  # Google container tags (ref https://developer.android.com/guide/topics/media/platform/hdr-image-format)
2112
- # NOTE: Not included because these namespace prefixes conflict with Google's depth-map Device tags!
2127
+ # NOTE: The namespace prefix used by ExifTool is 'GContainer' instead of 'Container'
2128
+ # dueo to a conflict with Google's depth-map Device 'Container' namespace!
2113
2129
  # (see ../pics/GooglePixel8Pro.jpg sample image)
2114
- # %Image::ExifTool::XMP::Container = (
2115
- # %xmpTableDefaults,
2116
- # GROUPS => { 1 => 'XMP-Container', 2 => 'Image' },
2117
- # NAMESPACE => 'Container',
2118
- # NOTES => 'Google Container namespace.',
2119
- # Directory => {
2120
- # Name => 'ContainerDirectory',
2121
- # FlatName => 'Directory',
2122
- # List => 'Seq',
2123
- # Struct => {
2124
- # STRUCT_NAME => 'Directory',
2125
- # Item => {
2126
- # Namespace => 'Container',
2127
- # Struct => {
2128
- # STRUCT_NAME => 'Item',
2129
- # NAMESPACE => { Item => 'http://ns.google.com/photos/1.0/container/item/'},
2130
- # Mime => { },
2131
- # Semantic => { },
2132
- # Length => { Writable => 'integer' },
2133
- # Label => { },
2134
- # Padding => { Writable => 'integer' },
2135
- # URI => { },
2136
- # },
2137
- # },
2138
- # },
2139
- # },
2140
- # );
2130
+ %Image::ExifTool::XMP::GContainer = (
2131
+ %xmpTableDefaults,
2132
+ GROUPS => { 1 => 'XMP-GContainer', 2 => 'Image' },
2133
+ NAMESPACE => 'GContainer',
2134
+ NOTES => q{
2135
+ Google Container namespace. ExifTool uses the prefix 'GContainer' instead
2136
+ of 'Container' to avoid a conflict with the Google Device Container
2137
+ namespace.
2138
+ },
2139
+ Directory => {
2140
+ Name => 'ContainerDirectory',
2141
+ FlatName => 'Directory',
2142
+ List => 'Seq',
2143
+ Struct => {
2144
+ STRUCT_NAME => 'Directory',
2145
+ Item => {
2146
+ Namespace => 'GContainer',
2147
+ Struct => {
2148
+ STRUCT_NAME => 'Item',
2149
+ # (use 'GItem' to avoid conflict with Google Device Container Item)
2150
+ NAMESPACE => { GItem => 'http://ns.google.com/photos/1.0/container/item/'},
2151
+ Mime => { },
2152
+ Semantic => { },
2153
+ Length => { Writable => 'integer' },
2154
+ Label => { },
2155
+ Padding => { Writable => 'integer' },
2156
+ URI => { },
2157
+ },
2158
+ },
2159
+ },
2160
+ },
2161
+ );
2141
2162
 
2142
2163
  # Getty Images namespace (ref PH)
2143
2164
  %Image::ExifTool::XMP::GettyImages = (
@@ -20,7 +20,7 @@ use strict;
20
20
  use vars qw($VERSION $warnString);
21
21
  use Image::ExifTool qw(:DataAccess :Utils);
22
22
 
23
- $VERSION = '1.31';
23
+ $VERSION = '1.32';
24
24
 
25
25
  sub WarnProc($) { $warnString = $_[0]; }
26
26
 
@@ -325,9 +325,13 @@ sub ProcessRAR($$)
325
325
  last if $size < 0;
326
326
  next unless $size; # ignore blocks with no data
327
327
  # don't try to read very large blocks unless LargeFileSupport is enabled
328
- if ($size >= 0x80000000 and not $et->Options('LargeFileSupport')) {
329
- $et->Warn('Large block encountered. Aborting.');
330
- last;
328
+ if ($size >= 0x80000000) {
329
+ if (not $et->Options('LargeFileSupport')) {
330
+ $et->Warn('Large block encountered. Aborting.');
331
+ last;
332
+ } elsif ($et->Options('LargeFileSupport') eq '2') {
333
+ $et->WarnOnce('Processing large block (LargeFileSupport is 2)');
334
+ }
331
335
  }
332
336
  # process the block
333
337
  if ($type == 0x74) { # file block
@@ -27,9 +27,9 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes
27
27
  %noWriteFile %magicNumber @langs $defaultLang %langName %charsetName
28
28
  %mimeType $swapBytes $swapWords $currentByteOrder %unpackStd
29
29
  %jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
30
- %static_vars);
30
+ %static_vars $advFmtSelf);
31
31
 
32
- $VERSION = '12.84';
32
+ $VERSION = '12.89';
33
33
  $RELEASE = '';
34
34
  @ISA = qw(Exporter);
35
35
  %EXPORT_TAGS = (
@@ -145,17 +145,18 @@ sub ReadValue($$$;$$$);
145
145
  SigmaRaw JPEG GIMP Jpeg2000 GIF BMP BMP::OS2 BMP::Extra BPG BPG::Extensions
146
146
  WPG ICO PICT PNG MNG FLIF DjVu DPX OpenEXR ZISRAW MRC LIF MRC::FEI12 MIFF
147
147
  PCX PGF PSP PhotoCD Radiance Other::PFM PDF PostScript Photoshop::Header
148
- Photoshop::Layers Photoshop::ImageData FujiFilm::RAF FujiFilm::IFD
149
- FujiFilm::MRAW Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD Sony::PMP ITC ID3
150
- ID3::Lyrics3 FLAC AAC Ogg Vorbis APE APE::NewHeader APE::OldHeader Audible
151
- MPC MPEG::Audio MPEG::Video MPEG::Xing M2TS QuickTime QuickTime::ImageFile
152
- QuickTime::Stream QuickTime::Tags360Fly Matroska Matroska::StdTag MOI MXF DV
153
- Flash Flash::FLV Real::Media Real::Audio Real::Metafile Red RIFF AIFF ASF
154
- WTV DICOM FITS XISF MIE JSON HTML XMP::SVG Palm Palm::MOBI Palm::EXTH
155
- Torrent EXE EXE::PEVersion EXE::PEString EXE::MachO EXE::PEF EXE::ELF
156
- EXE::AR EXE::CHM LNK Font VCard Text VCard::VCalendar VCard::VNote RSRC
157
- Rawzor ZIP ZIP::GZIP ZIP::RAR ZIP::RAR5 RTF OOXML iWork ISO FLIR::AFF
158
- FLIR::FPF MacOS MacOS::MDItem FlashPix::DocTable
148
+ Photoshop::Layers Photoshop::ImageData FujiFilm::RAFHeader FujiFilm::RAF
149
+ FujiFilm::IFD FujiFilm::MRAW Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD
150
+ Sony::PMP ITC ID3 ID3::Lyrics3 FLAC AAC Ogg Vorbis APE APE::NewHeader
151
+ APE::OldHeader Audible MPC MPEG::Audio MPEG::Video MPEG::Xing M2TS QuickTime
152
+ QuickTime::ImageFile QuickTime::Stream QuickTime::Tags360Fly Matroska
153
+ Matroska::StdTag MOI MXF DV Flash Flash::FLV Real::Media Real::Audio
154
+ Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS XISF MIE JSON HTML XMP::SVG
155
+ Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion EXE::PEString
156
+ EXE::MachO EXE::PEF EXE::ELF EXE::AR EXE::CHM LNK Font VCard Text
157
+ VCard::VCalendar VCard::VNote RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR ZIP::RAR5
158
+ RTF OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS MacOS::MDItem
159
+ FlashPix::DocTable
159
160
  );
160
161
 
161
162
  # alphabetical list of current Lang modules
@@ -198,7 +199,7 @@ $defaultLang = 'en'; # default language
198
199
  RAR 7Z BZ2 CZI TAR EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font
199
200
  JUMBF RSRC M2TS MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard
200
201
  LRI R3D AA PDB PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3 DICOM PCD
201
- ICO TXT AAC);
202
+ NKA ICO TXT AAC);
202
203
 
203
204
  # file types that we can write (edit)
204
205
  my @writeTypes = qw(JPEG TIFF GIF CRW MRW ORF RAF RAW PNG MIE PSD XMP PPM EPS
@@ -210,7 +211,7 @@ my %writeTypes; # lookup for writable file types (hash filled if required)
210
211
  # (See here for 3FR reason: https://exiftool.org/forum/index.php?msg=17570)
211
212
  %noWriteFile = (
212
213
  TIFF => [ qw(3FR DCR K25 KDC SRF) ],
213
- XMP => [ qw(SVG INX) ],
214
+ XMP => [ qw(SVG INX NXD) ],
214
215
  JP2 => [ qw(J2C JPC) ],
215
216
  MOV => [ qw(INSV) ],
216
217
  );
@@ -426,10 +427,12 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
426
427
  # NDPI => ['TIFF', 'Hamamatsu NanoZoomer Digital Pathology Image'],
427
428
  NEF => ['TIFF', 'Nikon (RAW) Electronic Format'],
428
429
  NEWER => 'COS',
430
+ NKA => ['NKA', 'Nikon NX Studio Adjustments'],
429
431
  NKSC => ['XMP', 'Nikon Sidecar'],
430
432
  NMBTEMPLATE => ['ZIP','Apple Numbers Template'],
431
433
  NRW => ['TIFF', 'Nikon RAW (2)'],
432
434
  NUMBERS => ['ZIP','Apple Numbers spreadsheet'],
435
+ NXD => ['XMP', 'Nikon NX-D Settings'],
433
436
  O => ['EXE', 'Relocatable Object'],
434
437
  ODB => ['ZIP', 'Open Document Database'],
435
438
  ODC => ['ZIP', 'Open Document Chart'],
@@ -869,6 +872,7 @@ my %moduleName = (
869
872
  MKV => 'Matroska',
870
873
  MP3 => 'ID3',
871
874
  MRW => 'MinoltaRaw',
875
+ NKA => 'Nikon',
872
876
  OGG => 'Ogg',
873
877
  ORF => 'Olympus',
874
878
  PDB => 'Palm',
@@ -972,6 +976,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
972
976
  MRC => '.{64}[\x01\x02\x03]\0\0\0[\x01\x02\x03]\0\0\0[\x01\x02\x03]\0\0\0.{132}MAP[\0 ](\x44\x44|\x44\x41|\x11\x11)\0\0',
973
977
  MRW => '\0MR[MI]',
974
978
  MXF => '\x06\x0e\x2b\x34\x02\x05\x01\x01\x0d\x01\x02', # (not tested if extension recognized)
979
+ NKA => 'NIKONADJ',
975
980
  OGG => '(OggS|ID3)',
976
981
  ORF => '(II|MM)',
977
982
  # PCD => signature is at byte 2048
@@ -1123,7 +1128,7 @@ my @availableOptions = (
1123
1128
  [ 'IgnoreTags', undef, 'list of tags to ignore when extracting' ],
1124
1129
  [ 'ImageHashType', 'MD5', 'image hash algorithm' ],
1125
1130
  [ 'Lang', $defaultLang, 'localized language for descriptions etc' ],
1126
- [ 'LargeFileSupport', undef, 'flag indicating support of 64-bit file offsets' ],
1131
+ [ 'LargeFileSupport', 1, 'flag indicating support of 64-bit file offsets' ],
1127
1132
  [ 'LimitLongValues', 60, 'length limit for long values' ],
1128
1133
  [ 'List', undef, '[deprecated, use ListSplit and ListJoin instead]' ],
1129
1134
  [ 'ListItem', undef, 'used to return a specific item from lists' ],
@@ -1269,6 +1274,7 @@ my %systemTagsNotes = (
1269
1274
  },
1270
1275
  Writable => 1,
1271
1276
  WritePseudo => 1,
1277
+ Priority => 2,
1272
1278
  DelCheck => q{"Can't delete"},
1273
1279
  Protected => 1,
1274
1280
  RawConv => '$self->ConvertFileName($val)',
@@ -1281,6 +1287,7 @@ my %systemTagsNotes = (
1281
1287
  WritePseudo => 1,
1282
1288
  DelCheck => q{"Can't delete"},
1283
1289
  Protected => 1,
1290
+ Priority => 2,
1284
1291
  Notes => q{
1285
1292
  may be written with a full path name to set FileName and Directory in one
1286
1293
  operation. This is such a powerful feature that a TestName tag is provided
@@ -1293,6 +1300,7 @@ my %systemTagsNotes = (
1293
1300
  },
1294
1301
  BaseName => {
1295
1302
  Groups => { 1 => 'System', 2 => 'Other' },
1303
+ Priority => 2,
1296
1304
  Notes => q{
1297
1305
  file name without extension. Not generated unless specifically requested or
1298
1306
  the API L<RequestAll|../ExifTool.html#RequestAll> option is set
@@ -1362,6 +1370,7 @@ my %systemTagsNotes = (
1362
1370
  },
1363
1371
  FileType => {
1364
1372
  Groups => { 2 => 'Other' },
1373
+ Priority => 2,
1365
1374
  Notes => q{
1366
1375
  a short description of the file type. For many file types this is the just
1367
1376
  the uppercase file extension
@@ -1807,6 +1816,7 @@ my %systemTagsNotes = (
1807
1816
  PrintConv => 'sprintf("%.3g s", $val)',
1808
1817
  },
1809
1818
  RAFVersion => { Notes => 'RAF file version number' },
1819
+ RAFCompression => { PrintConv => { 0 => 'Uncompressed', 2 => 'Compressed' } }, # 1 maybe lossy?
1810
1820
  JPEGDigest => {
1811
1821
  Notes => q{
1812
1822
  an MD5 digest of the JPEG quantization tables is combined with the component
@@ -2031,6 +2041,8 @@ my %systemTagsNotes = (
2031
2041
  my $lat = 1;
2032
2042
  foreach (@args) {
2033
2043
  next unless /^[-+]?\d/;
2044
+ my @reals = /\.\d+/g;
2045
+ next if @reals > 1; # (allow floating "lat lon" format)
2034
2046
  require Image::ExifTool::GPS;
2035
2047
  $_ = Image::ExifTool::GPS::ToDegrees($_, 1, $lat ? 'lat' : 'lon');
2036
2048
  $lat ^= 1;
@@ -2050,7 +2062,8 @@ my %systemTagsNotes = (
2050
2062
  GeolocationCountry => { %geoInfo, Notes => 'geolocation country name', ValueConv => '$self->Decode($val,"UTF8")' },
2051
2063
  GeolocationCountryCode=>{%geoInfo, Notes => 'geolocation country code' },
2052
2064
  GeolocationTimeZone => { %geoInfo, Notes => 'geolocation time zone ID' },
2053
- GeolocationFeatureCode=>{%geoInfo, Notes => 'feature code, see L<http://www.geonames.org/export/codes.html#P>' },
2065
+ GeolocationFeatureCode=>{%geoInfo, Notes => 'geolocation feature code, see L<http://www.geonames.org/export/codes.html#P>' },
2066
+ GeolocationFeatureType=>{%geoInfo, Notes => 'geolocation feature type' },
2054
2067
  GeolocationPopulation=>{ %geoInfo, Notes => 'city population rounded to 2 significant digits' },
2055
2068
  GeolocationDistance => { %geoInfo, Notes => 'distance in km from current GPS to city', PrintConv => '"$val km"' },
2056
2069
  GeolocationPosition => { %geoInfo, Notes => 'approximate GPS coordinates of city',
@@ -2796,6 +2809,7 @@ sub ExtractInfo($;@)
2796
2809
  # (note that Windows directories will still show the
2797
2810
  # daylight savings time bug -- should fix this sometime)
2798
2811
  @stat = stat $$raf{FILE_PT};
2812
+ $stat[7] = undef if -p $$raf{FILE_PT}; # (pipe buffer size isn't useful)
2799
2813
  }
2800
2814
  my $fileSize = $stat[7];
2801
2815
  $self->FoundTag('FileSize', $stat[7]) if defined $stat[7];
@@ -4144,7 +4158,8 @@ sub GetFileType(;$$)
4144
4158
  #------------------------------------------------------------------------------
4145
4159
  # Return true if we can write the specified file type
4146
4160
  # Inputs: 0) file name or ext
4147
- # Returns: true if writable, 0 if not writable, undef if unrecognized
4161
+ # Returns: true if writable, 0 if not writable, '' if not writable due to extension,
4162
+ # undef if unrecognized
4148
4163
  sub CanWrite($)
4149
4164
  {
4150
4165
  local $_;
@@ -4153,7 +4168,7 @@ sub CanWrite($)
4153
4168
  if ($noWriteFile{$type}) {
4154
4169
  # can't write TIFF files with certain extensions (various RAW formats)
4155
4170
  my $ext = GetFileExtension($file) || uc($file);
4156
- return grep(/^$ext$/, @{$noWriteFile{$type}}) ? 0 : 1 if $ext;
4171
+ return grep(/^$ext$/, @{$noWriteFile{$type}}) ? '' : 1 if $ext;
4157
4172
  }
4158
4173
  if ($onlyWriteFile{$type}) {
4159
4174
  my $ext = GetFileExtension($file) || uc($file);
@@ -4387,6 +4402,7 @@ sub DoneExtract($)
4387
4402
  $self->FoundTag(GeolocationCountry => $geo[4]) if $geo[4];
4388
4403
  $self->FoundTag(GeolocationTimeZone => $geo[5]) if $geo[5];
4389
4404
  $self->FoundTag(GeolocationFeatureCode => $geo[6]);
4405
+ $self->FoundTag(GeolocationFeatureType => $geo[10]) if $geo[10];
4390
4406
  $self->FoundTag(GeolocationPopulation => $geo[7]);
4391
4407
  $self->FoundTag(GeolocationPosition => "$geo[8] $geo[9]");
4392
4408
  if ($dist) {
@@ -6849,11 +6865,12 @@ sub DirStart($$;$)
6849
6865
  #------------------------------------------------------------------------------
6850
6866
  # Extract metadata from a jpg image
6851
6867
  # Inputs: 0) ExifTool object reference, 1) dirInfo ref with RAF set
6868
+ # 2) tag table ref to process JPEG-like metadata
6852
6869
  # Returns: 1 on success, 0 if this wasn't a valid JPEG file
6853
- sub ProcessJPEG($$)
6870
+ sub ProcessJPEG($$;$)
6854
6871
  {
6855
6872
  local $_;
6856
- my ($self, $dirInfo) = @_;
6873
+ my ($self, $dirInfo, $optionalTagTable) = @_;
6857
6874
  my $options = $$self{OPTIONS};
6858
6875
  my $verbose = $$options{Verbose};
6859
6876
  my $out = $$options{TextOut};
@@ -6861,20 +6878,29 @@ sub ProcessJPEG($$)
6861
6878
  my $raf = $$dirInfo{RAF};
6862
6879
  my $req = $$self{REQ_TAG_LOOKUP};
6863
6880
  my $htmlDump = $$self{HTML_DUMP};
6864
- my %dumpParms = ( Out => $out );
6865
- my ($ch, $s, $length, $hash, $hashsize);
6881
+ my %dumpParms = ( Out => $out, Prefix => $$self{INDENT} );
6882
+ my ($ch, $s, $length, $hash, $hashsize, $indent);
6866
6883
  my ($success, $wantTrailer, $trailInfo, $foundSOS, $gotSize, %jumbfChunk);
6867
6884
  my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal);
6868
6885
  my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP);
6869
6886
 
6887
+ ($indent = $$self{INDENT}) =~ s/ $//;
6888
+ unless ($raf) {
6889
+ $raf = File::RandomAccess->new($$dirInfo{DataPt});
6890
+ $self->VerboseDir('JPEG', undef, length(${$$dirInfo{DataPt}}));
6891
+ }
6870
6892
  # get pointer to hash object if it exists and we are the top-level JPEG or JP2
6871
6893
  if ($$self{FILE_TYPE} =~ /^(JPEG|JP2)$/ and not $$self{DOC_NUM}) {
6872
6894
  $hash = $$self{ImageDataHash};
6873
6895
  $hashsize = 0;
6874
6896
  }
6875
-
6876
6897
  # check to be sure this is a valid JPG (or J2C, or EXV) file
6877
- return 0 unless $raf->Read($s, 2) == 2 and $s =~ /^\xff[\xd8\x4f\x01]/;
6898
+ if ($raf->Read($s, 2) == 2 and $s =~ /^\xff[\xd8\x4f\x01]/) {
6899
+ undef $optionalTagTable;
6900
+ } else {
6901
+ return 0 unless $optionalTagTable and $s =~ /^\xff[\xe0-\xef]/;
6902
+ $raf->Seek(-2, 1) or $self->Error('Seek error'), return 1;
6903
+ }
6878
6904
  if ($s eq "\xff\x01") {
6879
6905
  return 0 unless $raf->Read($s, 5) == 5 and $s eq 'Exiv2';
6880
6906
  $$self{FILE_TYPE} = 'EXV';
@@ -6892,7 +6918,7 @@ sub ProcessJPEG($$)
6892
6918
  $$raf{NoBuffer} = 1 if $self->Options('FastScan'); # disable buffering in FastScan mode
6893
6919
 
6894
6920
  $dumpParms{MaxLen} = 128 if $verbose < 4;
6895
- if ($htmlDump) {
6921
+ if ($htmlDump and not $optionalTagTable) {
6896
6922
  $dumpEnd = $raf->Tell();
6897
6923
  my ($n, $t, $m) = $s eq 'Exiv2' ? (7,'EXV','TEM') : (2,'JPEG','SOI');
6898
6924
  my $pos = $dumpEnd - $n;
@@ -6911,6 +6937,7 @@ sub ProcessJPEG($$)
6911
6937
  Marker: for (;;) {
6912
6938
  # set marker and data pointer for current segment
6913
6939
  my $marker = $nextMarker;
6940
+ last if $marker and $marker < 0;
6914
6941
  my $segDataPt = $nextSegDataPt;
6915
6942
  my $segPos = $nextSegPos;
6916
6943
  my $skipped;
@@ -6919,12 +6946,17 @@ sub ProcessJPEG($$)
6919
6946
  #
6920
6947
  # read ahead to the next segment unless we have reached EOI, SOS or SOD
6921
6948
  #
6922
- unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer and not $hash) or
6949
+ until ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer and not $hash) or
6923
6950
  $marker==0x93))
6924
6951
  {
6925
6952
  # read up to next marker (JPEG markers begin with 0xff)
6926
6953
  my $buff;
6927
- $raf->ReadLine($buff) or last;
6954
+ unless ($raf->ReadLine($buff)) {
6955
+ last Marker unless $optionalTagTable;
6956
+ $nextMarker = -1;
6957
+ $success = 1;
6958
+ last;
6959
+ }
6928
6960
  $skipped = length($buff) - 1;
6929
6961
  # JPEG markers can be padded with unlimited 0xff's
6930
6962
  for (;;) {
@@ -6936,21 +6968,21 @@ sub ProcessJPEG($$)
6936
6968
  # read segment data if it exists
6937
6969
  if (not defined $markerLenBytes{$nextMarker}) {
6938
6970
  # read record length word
6939
- last unless $raf->Read($s, 2) == 2;
6971
+ last Marker unless $raf->Read($s, 2) == 2;
6940
6972
  my $len = unpack('n',$s); # get data length
6941
- last unless defined($len) and $len >= 2;
6973
+ last Marker unless defined($len) and $len >= 2;
6942
6974
  $nextSegPos = $raf->Tell();
6943
6975
  $len -= 2; # subtract size of length word
6944
- last unless $raf->Read($buff, $len) == $len;
6976
+ last Marker unless $raf->Read($buff, $len) == $len;
6945
6977
  $nextSegDataPt = \$buff; # set pointer to our next data
6946
6978
  } elsif ($markerLenBytes{$nextMarker} == 4) {
6947
6979
  # handle J2C extensions with 4-byte length word
6948
- last unless $raf->Read($s, 4) == 4;
6980
+ last Marker unless $raf->Read($s, 4) == 4;
6949
6981
  my $len = unpack('N',$s); # get data length
6950
- last unless defined($len) and $len >= 4;
6982
+ last Marker unless defined($len) and $len >= 4;
6951
6983
  $nextSegPos = $raf->Tell();
6952
6984
  $len -= 4; # subtract size of length word
6953
- last unless $raf->Seek($len, 1);
6985
+ last Marker unless $raf->Seek($len, 1);
6954
6986
  } elsif ($hash and defined $marker and ($marker == 0x00 or $marker == 0xda or
6955
6987
  ($marker >= 0xd0 and $marker <= 0xd7)))
6956
6988
  {
@@ -6966,7 +6998,8 @@ sub ProcessJPEG($$)
6966
6998
  $hashsize += $skipped + 2;
6967
6999
  }
6968
7000
  # read second segment too if this was the first
6969
- next unless defined $marker;
7001
+ next Marker unless defined $marker;
7002
+ last;
6970
7003
  }
6971
7004
  # set some useful variables for the current segment
6972
7005
  my $markerName = JpegMarkerName($marker);
@@ -6986,7 +7019,7 @@ sub ProcessJPEG($$)
6986
7019
  if (($marker & 0xf0) == 0xc0 and ($marker == 0xc0 or $marker & 0x03)) {
6987
7020
  $length = length $$segDataPt;
6988
7021
  if ($verbose) {
6989
- print $out "JPEG $markerName ($length bytes):\n";
7022
+ print $out "${indent}JPEG $markerName ($length bytes):\n";
6990
7023
  HexDump($segDataPt, undef, %dumpParms, Addr=>$segPos) if $verbose>2;
6991
7024
  } elsif ($htmlDump) {
6992
7025
  $self->HDump($segPos-4, $length+4, "[JPEG $markerName]", undef, 0x08);
@@ -7029,7 +7062,7 @@ sub ProcessJPEG($$)
7029
7062
  next;
7030
7063
  } elsif ($marker == 0xd9) { # EOI
7031
7064
  pop @$path;
7032
- $verbose and print $out "JPEG EOI\n";
7065
+ $verbose and print $out "${indent}JPEG EOI\n";
7033
7066
  my $pos = $raf->Tell();
7034
7067
  $$self{TrailerStart} = $pos unless $$self{DOC_NUM};
7035
7068
  if ($htmlDump and $dumpEnd) {
@@ -7090,7 +7123,7 @@ sub ProcessJPEG($$)
7090
7123
  # adjust PreviewImageStart to this location
7091
7124
  my $actual = $pos + pos($buff) - 4;
7092
7125
  if ($start and $start ne $actual and $verbose > 1) {
7093
- print $out "(Fixed PreviewImage location: $start -> $actual)\n";
7126
+ print $out "${indent}(Fixed PreviewImage location: $start -> $actual)\n";
7094
7127
  }
7095
7128
  # update preview image offsets
7096
7129
  if ($start) {
@@ -7144,7 +7177,7 @@ sub ProcessJPEG($$)
7144
7177
  pop @$path;
7145
7178
  $foundSOS = 1;
7146
7179
  # all done with meta information unless we have a trailer
7147
- $verbose and print $out "JPEG SOS\n";
7180
+ $verbose and print $out "${indent}JPEG SOS\n";
7148
7181
  unless ($fast) {
7149
7182
  $trailInfo = IdentifyTrailer($raf);
7150
7183
  # process trailer now unless we are doing verbose dump
@@ -7184,7 +7217,7 @@ sub ProcessJPEG($$)
7184
7217
  last; # all done parsing file
7185
7218
  } elsif ($marker == 0x93) {
7186
7219
  pop @$path;
7187
- $verbose and print $out "JPEG SOD\n";
7220
+ $verbose and print $out "${indent}JPEG SOD\n";
7188
7221
  $success = 1;
7189
7222
  if ($hash and $$self{FILE_TYPE} eq 'JP2') {
7190
7223
  my $pos = $raf->Tell();
@@ -7195,7 +7228,7 @@ sub ProcessJPEG($$)
7195
7228
  last; # all done parsing file
7196
7229
  } elsif (defined $markerLenBytes{$marker}) {
7197
7230
  # handle other stand-alone markers and segments we skipped over
7198
- $verbose and $marker and print $out "JPEG $markerName\n";
7231
+ $verbose and $marker and print $out "${indent}JPEG $markerName\n";
7199
7232
  next;
7200
7233
  } elsif ($marker == 0xdb and length($$segDataPt) and # DQT
7201
7234
  # save the DQT data only if JPEGDigest has been requested
@@ -7215,7 +7248,7 @@ sub ProcessJPEG($$)
7215
7248
  $length = length $$segDataPt;
7216
7249
  $appBytes += $length + 4 if ($marker & 0xf0) == 0xe0; # total size of APP segments
7217
7250
  if ($verbose) {
7218
- print $out "JPEG $markerName ($length bytes):\n";
7251
+ print $out "${indent}JPEG $markerName ($length bytes):\n";
7219
7252
  if ($verbose > 2) {
7220
7253
  my %extraParms = ( Addr => $segPos );
7221
7254
  $extraParms{MaxLen} = 128 if $verbose == 4;
@@ -7373,7 +7406,7 @@ sub ProcessJPEG($$)
7373
7406
  # some software erroneously writes zeros for the chunk counts)
7374
7407
  my $chunkNum = Get8u($segDataPt, 6);
7375
7408
  my $chunksTot = Get8u($segDataPt, 7) + 1; # (note the "+ 1"!)
7376
- $verbose and printf $out "$$self{INDENT}FLIR chunk %d of %d\n",
7409
+ $verbose and printf $out "${indent}FLIR chunk %d of %d\n",
7377
7410
  $chunkNum + 1, $chunksTot;
7378
7411
  if (defined $flirTotal) {
7379
7412
  # abort parsing FLIR if the total chunk count is inconsistent
@@ -7438,7 +7471,7 @@ sub ProcessJPEG($$)
7438
7471
  # some software erroneously writes zeros for the chunk counts)
7439
7472
  my $chunkNum = Get8u($segDataPt, 12);
7440
7473
  my $chunksTot = Get8u($segDataPt, 13);
7441
- $verbose and print $out "$$self{INDENT}ICC_Profile chunk $chunkNum of $chunksTot\n";
7474
+ $verbose and print $out "${indent}ICC_Profile chunk $chunkNum of $chunksTot\n";
7442
7475
  if (defined $iccChunksTotal) {
7443
7476
  # abort parsing ICC_Profile if the total chunk count is inconsistent
7444
7477
  undef $iccChunkCount if $chunksTot != $iccChunksTotal;
@@ -7991,7 +8024,7 @@ sub ProcessJPEG($$)
7991
8024
  }
7992
8025
  }
7993
8026
  # print verbose hash message if necessary
7994
- print $out "$$self{INDENT}(ImageDataHash: $hashsize bytes of JPEG image data)\n" if $hashsize and $verbose;
8027
+ print $out "${indent}(ImageDataHash: $hashsize bytes of JPEG image data)\n" if $hashsize and $verbose;
7995
8028
  # calculate JPEGDigest if requested
7996
8029
  if (@dqt) {
7997
8030
  require Image::ExifTool::JPEGDigest;