ExifTool.pm (Image-ExifTool-12.57) | : | ExifTool.pm (Image-ExifTool-12.58) | ||
---|---|---|---|---|
skipping to change at line 32 | skipping to change at line 32 | |||
use overload; | use overload; | |||
use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes | use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes | |||
%allTables @tableOrder $exifAPP1hdr $xmpAPP1hdr $xmpExtAPP1hdr | %allTables @tableOrder $exifAPP1hdr $xmpAPP1hdr $xmpExtAPP1hdr | |||
$psAPP13hdr $psAPP13old @loadAllTables %UserDefined $evalWarning | $psAPP13hdr $psAPP13old @loadAllTables %UserDefined $evalWarning | |||
%noWriteFile %magicNumber @langs $defaultLang %langName %charsetName | %noWriteFile %magicNumber @langs $defaultLang %langName %charsetName | |||
%mimeType $swapBytes $swapWords $currentByteOrder %unpackStd | %mimeType $swapBytes $swapWords $currentByteOrder %unpackStd | |||
%jpegMarker %specialTags %fileTypeLookup $testLen $exeDir | %jpegMarker %specialTags %fileTypeLookup $testLen $exeDir | |||
%static_vars); | %static_vars); | |||
$VERSION = '12.57'; | $VERSION = '12.58'; | |||
$RELEASE = ''; | $RELEASE = ''; | |||
@ISA = qw(Exporter); | @ISA = qw(Exporter); | |||
%EXPORT_TAGS = ( | %EXPORT_TAGS = ( | |||
# all public non-object-oriented functions: | # all public non-object-oriented functions: | |||
Public => [qw( | Public => [qw( | |||
ImageInfo GetTagName GetShortcuts GetAllTags GetWritableTags | ImageInfo GetTagName GetShortcuts GetAllTags GetWritableTags | |||
GetAllGroups GetDeleteGroups GetFileType CanWrite CanCreate | GetAllGroups GetDeleteGroups GetFileType CanWrite CanCreate | |||
AddUserDefinedTags | AddUserDefinedTags | |||
)], | )], | |||
# exports not part of the public API, but used by ExifTool modules: | # exports not part of the public API, but used by ExifTool modules: | |||
skipping to change at line 1824 | skipping to change at line 1824 | |||
SphericalVideoXML => { | SphericalVideoXML => { | |||
Groups => { 0 => 'QuickTime', 1 => 'GSpherical', 2 => 'Video' }, | Groups => { 0 => 'QuickTime', 1 => 'GSpherical', 2 => 'Video' }, | |||
# (group 1 is 'GSpherical' to trigger creation of this tag when writing, | # (group 1 is 'GSpherical' to trigger creation of this tag when writing, | |||
# but when reading the family 1 group is the track number) | # but when reading the family 1 group is the track number) | |||
Flags => [ 'Writable', 'Binary', 'Protected' ], | Flags => [ 'Writable', 'Binary', 'Protected' ], | |||
Notes => q{ | Notes => q{ | |||
the SphericalVideoXML block from MP4/MOV videos. This tag is genera ted only | the SphericalVideoXML block from MP4/MOV videos. This tag is genera ted only | |||
if specifically requested | if specifically requested | |||
}, | }, | |||
}, | }, | |||
ImageDataMD5 => { | ||||
Notes => q{ | ||||
MD5 of image data. Generated only if specifically requested for JPEG | ||||
and | ||||
TIFF-based images, except Panasonic raw for now. Includes image data | ||||
, | ||||
OtherImage and JpgFromRaw in the MD5, but not ThumbnailImage or Prev | ||||
iewImage | ||||
}, | ||||
}, | ||||
); | ); | |||
# tags defined by UserParam option (added at runtime) | # tags defined by UserParam option (added at runtime) | |||
%Image::ExifTool::UserParam = ( | %Image::ExifTool::UserParam = ( | |||
GROUPS => { 0 => 'UserParam', 1 => 'UserParam', 2 => 'Other' }, | GROUPS => { 0 => 'UserParam', 1 => 'UserParam', 2 => 'Other' }, | |||
PRIORITY => 0, | PRIORITY => 0, | |||
); | ); | |||
# YCbCrSubSampling values (used by JPEG SOF, EXIF and XMP) | # YCbCrSubSampling values (used by JPEG SOF, EXIF and XMP) | |||
%Image::ExifTool::JPEG::yCbCrSubSampling = ( | %Image::ExifTool::JPEG::yCbCrSubSampling = ( | |||
skipping to change at line 2483 | skipping to change at line 2490 | |||
# generate sequence number if necessary | # generate sequence number if necessary | |||
$self->FoundTag('FileSequence', $$self{FILE_SEQUENCE}) if $$req{filesequ ence} or $reqAll; | $self->FoundTag('FileSequence', $$self{FILE_SEQUENCE}) if $$req{filesequ ence} or $reqAll; | |||
if ($$req{processingtime} or $reqAll) { | if ($$req{processingtime} or $reqAll) { | |||
eval { require Time::HiRes; @startTime = Time::HiRes::gettimeofday() }; | eval { require Time::HiRes; @startTime = Time::HiRes::gettimeofday() }; | |||
if (not @startTime and $$req{processingtime}) { | if (not @startTime and $$req{processingtime}) { | |||
$self->WarnOnce('Install Time::HiRes to generate ProcessingTime' ); | $self->WarnOnce('Install Time::HiRes to generate ProcessingTime' ); | |||
} | } | |||
} | } | |||
# create MD5 object if ImageDataMD5 is requested | ||||
if ($$req{imagedatamd5} and not $$self{ImageDataMD5}) { | ||||
if (require Digest::MD5) { | ||||
$$self{ImageDataMD5} = Digest::MD5->new; | ||||
} else { | ||||
$self->WarnOnce('Install Digest::MD5 to calculate image data MD5 | ||||
'); | ||||
} | ||||
} | ||||
++$$self{FILE_SEQUENCE}; # count files read | ++$$self{FILE_SEQUENCE}; # count files read | |||
} | } | |||
my $filename = $$self{FILENAME}; # image file name ('' if already open) | my $filename = $$self{FILENAME}; # image file name ('' if already open) | |||
my $raf = $$self{RAF}; # RandomAccess object | my $raf = $$self{RAF}; # RandomAccess object | |||
local *EXIFTOOL_FILE; # avoid clashes with global namespace | local *EXIFTOOL_FILE; # avoid clashes with global namespace | |||
my $realname = $filename; | my $realname = $filename; | |||
unless ($raf) { | unless ($raf) { | |||
skipping to change at line 2873 | skipping to change at line 2888 | |||
} | } | |||
} | } | |||
# restore original options | # restore original options | |||
%saveOptions and $$self{OPTIONS} = \%saveOptions; | %saveOptions and $$self{OPTIONS} = \%saveOptions; | |||
if ($reEntry) { | if ($reEntry) { | |||
# restore necessary members when exiting re-entrant code | # restore necessary members when exiting re-entrant code | |||
$$self{$_} = $$reEntry{$_} foreach keys %$reEntry; | $$self{$_} = $$reEntry{$_} foreach keys %$reEntry; | |||
SetByteOrder($saveOrder); | SetByteOrder($saveOrder); | |||
} elsif ($$self{ImageDataMD5}) { | ||||
my $digest = $$self{ImageDataMD5}->hexdigest; | ||||
# (don't store empty digest) | ||||
$self->FoundTag(ImageDataMD5 => $digest) unless $digest eq 'd41d8cd98f00 | ||||
b204e9800998ecf8427e'; | ||||
} | } | |||
# ($type may be undef without an Error when processing sub-documents) | # ($type may be undef without an Error when processing sub-documents) | |||
return 0 if not defined $type or exists $$self{VALUE}{Error}; | return 0 if not defined $type or exists $$self{VALUE}{Error}; | |||
return 1; | return 1; | |||
} | } | |||
#------------------------------------------------------------------------------ | #------------------------------------------------------------------------------ | |||
# Get hash of extracted meta information | # Get hash of extracted meta information | |||
# Inputs: 0) ExifTool object reference | # Inputs: 0) ExifTool object reference | |||
skipping to change at line 4300 | skipping to change at line 4319 | |||
return @rtn if defined $rtn[0]; | return @rtn if defined $rtn[0]; | |||
} | } | |||
$self->Warn("GetFileTime error for '${file}'"); | $self->Warn("GetFileTime error for '${file}'"); | |||
return (); | return (); | |||
} | } | |||
$file = *FH; # (not \*FH, so *FH will be kept open until $file goes out of scope) | $file = *FH; # (not \*FH, so *FH will be kept open until $file goes out of scope) | |||
} | } | |||
# on Windows, try to work around incorrect file times when daylight saving t ime is in effect | # on Windows, try to work around incorrect file times when daylight saving t ime is in effect | |||
if ($^O eq 'MSWin32') { | if ($^O eq 'MSWin32') { | |||
if (not eval { require Win32::API }) { | if (not eval { require Win32::API }) { | |||
$self->WarnOnce('Install Win32::API for proper handling of Windows f ile times'); | $self->WarnOnce('Install Win32::API for proper handling of Windows f ile times', 1); | |||
} elsif (not eval { require Win32API::File }) { | } elsif (not eval { require Win32API::File }) { | |||
$self->WarnOnce('Install Win32API::File for proper handling of Windo ws file times'); | $self->WarnOnce('Install Win32API::File for proper handling of Windo ws file times', 1); | |||
} else { | } else { | |||
# get Win32 handle, needed for GetFileTime | # get Win32 handle, needed for GetFileTime | |||
my $win32Handle = eval { Win32API::File::GetOsFHandle($file) }; | my $win32Handle = eval { Win32API::File::GetOsFHandle($file) }; | |||
unless ($win32Handle) { | unless ($win32Handle) { | |||
$self->Warn("Win32API::File::GetOsFHandle returned invalid handl e"); | $self->Warn("Win32API::File::GetOsFHandle returned invalid handl e"); | |||
return (); | return (); | |||
} | } | |||
# get FILETIME structs | # get FILETIME structs | |||
my ($atime, $mtime, $ctime, $time); | my ($atime, $mtime, $ctime, $time); | |||
$atime = $mtime = $ctime = pack 'LL', 0, 0; | $atime = $mtime = $ctime = pack 'LL', 0, 0; | |||
skipping to change at line 5871 | skipping to change at line 5890 | |||
} else { | } else { | |||
$val = sprintf("%.1f days", $val / (24 * 3600)); | $val = sprintf("%.1f days", $val / (24 * 3600)); | |||
} | } | |||
} | } | |||
return $val; | return $val; | |||
} | } | |||
#------------------------------------------------------------------------------ | #------------------------------------------------------------------------------ | |||
# Patched timelocal() that fixes ActivePerl timezone bug | # Patched timelocal() that fixes ActivePerl timezone bug | |||
# Inputs/Returns: same as timelocal() | # Inputs/Returns: same as timelocal() | |||
# Notes: must 'require Time::Local' before calling this routine | # Notes: must 'require Time::Local' before calling this routine. | |||
# Also note that year should be full year, and not relative to 1900 as with loca | ||||
ltime | ||||
sub TimeLocal(@) | sub TimeLocal(@) | |||
{ | { | |||
my $tm = Time::Local::timelocal(@_); | my $tm = Time::Local::timelocal(@_); | |||
if ($^O eq 'MSWin32') { | if ($^O eq 'MSWin32') { | |||
# patch for ActivePerl timezone bug | # patch for ActivePerl timezone bug | |||
my @t2 = localtime($tm); | my @t2 = localtime($tm); | |||
my $t2 = Time::Local::timelocal(@t2); | my $t2 = Time::Local::timelocal(@t2); | |||
# adjust timelocal() return value to be consistent with localtime() | # adjust timelocal() return value to be consistent with localtime() | |||
$tm += $tm - $t2; | $tm += $tm - $t2; | |||
} | } | |||
skipping to change at line 6341 | skipping to change at line 6361 | |||
my $options = $$self{OPTIONS}; | my $options = $$self{OPTIONS}; | |||
my $verbose = $$options{Verbose}; | my $verbose = $$options{Verbose}; | |||
my $out = $$options{TextOut}; | my $out = $$options{TextOut}; | |||
my $fast = $$options{FastScan} || 0; | my $fast = $$options{FastScan} || 0; | |||
my $raf = $$dirInfo{RAF}; | my $raf = $$dirInfo{RAF}; | |||
my $req = $$self{REQ_TAG_LOOKUP}; | my $req = $$self{REQ_TAG_LOOKUP}; | |||
my $htmlDump = $$self{HTML_DUMP}; | my $htmlDump = $$self{HTML_DUMP}; | |||
my %dumpParms = ( Out => $out ); | my %dumpParms = ( Out => $out ); | |||
my ($success, $wantTrailer, $trailInfo, $foundSOS, %jumbfChunk); | my ($success, $wantTrailer, $trailInfo, $foundSOS, %jumbfChunk); | |||
my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $fli rTotal); | my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $fli rTotal); | |||
my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP); | my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP, $md5); | |||
# get pointer to MD5 object if it exists and we are the top-level JPEG | ||||
$md5 = $$self{ImageDataMD5} if $$self{FILE_TYPE} eq 'JPEG' and not $$self{DO | ||||
C_NUM}; | ||||
# check to be sure this is a valid JPG (or J2C, or EXV) file | # check to be sure this is a valid JPG (or J2C, or EXV) file | |||
return 0 unless $raf->Read($s, 2) == 2 and $s =~ /^\xff[\xd8\x4f\x01]/; | return 0 unless $raf->Read($s, 2) == 2 and $s =~ /^\xff[\xd8\x4f\x01]/; | |||
if ($s eq "\xff\x01") { | if ($s eq "\xff\x01") { | |||
return 0 unless $raf->Read($s, 5) == 5 and $s eq 'Exiv2'; | return 0 unless $raf->Read($s, 5) == 5 and $s eq 'Exiv2'; | |||
$$self{FILE_TYPE} = 'EXV'; | $$self{FILE_TYPE} = 'EXV'; | |||
} | } | |||
my $appBytes = 0; | my $appBytes = 0; | |||
my $calcImageLen = $$req{jpegimagelength}; | my $calcImageLen = $$req{jpegimagelength}; | |||
if ($$options{RequestAll} and $$options{RequestAll} > 2) { | if ($$options{RequestAll} and $$options{RequestAll} > 2) { | |||
skipping to change at line 6389 | skipping to change at line 6412 | |||
# set marker and data pointer for current segment | # set marker and data pointer for current segment | |||
my $marker = $nextMarker; | my $marker = $nextMarker; | |||
my $segDataPt = $nextSegDataPt; | my $segDataPt = $nextSegDataPt; | |||
my $segPos = $nextSegPos; | my $segPos = $nextSegPos; | |||
my $skipped; | my $skipped; | |||
undef $nextMarker; | undef $nextMarker; | |||
undef $nextSegDataPt; | undef $nextSegDataPt; | |||
# | # | |||
# read ahead to the next segment unless we have reached EOI, SOS or SOD | # read ahead to the next segment unless we have reached EOI, SOS or SOD | |||
# | # | |||
unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTraile | unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTraile | |||
r) or $marker==0x93)) { | r and not $md5) or | |||
$marker==0x93)) | ||||
{ | ||||
# read up to next marker (JPEG markers begin with 0xff) | # read up to next marker (JPEG markers begin with 0xff) | |||
my $buff; | my $buff; | |||
$raf->ReadLine($buff) or last; | $raf->ReadLine($buff) or last; | |||
$skipped = length($buff) - 1; | $skipped = length($buff) - 1; | |||
# JPEG markers can be padded with unlimited 0xff's | # JPEG markers can be padded with unlimited 0xff's | |||
for (;;) { | for (;;) { | |||
$raf->Read($ch, 1) or last Marker; | $raf->Read($ch, 1) or last Marker; | |||
$nextMarker = ord($ch); | $nextMarker = ord($ch); | |||
last unless $nextMarker == 0xff; | last unless $nextMarker == 0xff; | |||
++$skipped; | ++$skipped; | |||
skipping to change at line 6419 | skipping to change at line 6444 | |||
last unless $raf->Read($buff, $len) == $len; | last unless $raf->Read($buff, $len) == $len; | |||
$nextSegDataPt = \$buff; # set pointer to our next data | $nextSegDataPt = \$buff; # set pointer to our next data | |||
} elsif ($markerLenBytes{$nextMarker} == 4) { | } elsif ($markerLenBytes{$nextMarker} == 4) { | |||
# handle J2C extensions with 4-byte length word | # handle J2C extensions with 4-byte length word | |||
last unless $raf->Read($s, 4) == 4; | last unless $raf->Read($s, 4) == 4; | |||
my $len = unpack('N',$s); # get data length | my $len = unpack('N',$s); # get data length | |||
last unless defined($len) and $len >= 4; | last unless defined($len) and $len >= 4; | |||
$nextSegPos = $raf->Tell(); | $nextSegPos = $raf->Tell(); | |||
$len -= 4; # subtract size of length word | $len -= 4; # subtract size of length word | |||
last unless $raf->Seek($len, 1); | last unless $raf->Seek($len, 1); | |||
} elsif ($md5 and defined $marker and ($marker == 0x00 or $marker == | ||||
0xda)) { | ||||
$md5->add($buff); # (note: this includes the terminating 0xff' | ||||
s) | ||||
} | } | |||
# read second segment too if this was the first | # read second segment too if this was the first | |||
next unless defined $marker; | next unless defined $marker; | |||
} | } | |||
# set some useful variables for the current segment | # set some useful variables for the current segment | |||
my $markerName = JpegMarkerName($marker); | my $markerName = JpegMarkerName($marker); | |||
$$path[$pn] = $markerName; | $$path[$pn] = $markerName; | |||
# issue warning if we skipped some garbage | # issue warning if we skipped some garbage | |||
if ($skipped and not $foundSOS and $markerName ne 'SOS') { | if ($skipped and not $foundSOS and $markerName ne 'SOS') { | |||
$self->Warn("Skipped unknown $skipped bytes after JPEG $markerName s egment", 1); | $self->Warn("Skipped unknown $skipped bytes after JPEG $markerName s egment", 1); | |||
skipping to change at line 6629 | skipping to change at line 6656 | |||
if ($$self{LeicaTrailer}) { | if ($$self{LeicaTrailer}) { | |||
require Image::ExifTool::Panasonic; | require Image::ExifTool::Panasonic; | |||
Image::ExifTool::Panasonic::ProcessLeicaTrailer($self); | Image::ExifTool::Panasonic::ProcessLeicaTrailer($self); | |||
$wantTrailer = 1 if $$self{LeicaTrailer}; | $wantTrailer = 1 if $$self{LeicaTrailer}; | |||
} else { | } else { | |||
$wantTrailer = 1 if $$options{ExtractEmbedded}; | $wantTrailer = 1 if $$options{ExtractEmbedded}; | |||
} | } | |||
next if $trailInfo or $wantTrailer or $verbose > 2 or $htmlDump; | next if $trailInfo or $wantTrailer or $verbose > 2 or $htmlDump; | |||
} | } | |||
# must scan to EOI if Validate or JpegCompressionFactor used | # must scan to EOI if Validate or JpegCompressionFactor used | |||
next if $$options{Validate} or $calcImageLen or $$req{trailer}; | next if $$options{Validate} or $calcImageLen or $$req{trailer} or $m d5; | |||
# nothing interesting to parse after start of scan (SOS) | # nothing interesting to parse after start of scan (SOS) | |||
$success = 1; | $success = 1; | |||
last; # all done parsing file | last; # all done parsing file | |||
} elsif ($marker == 0x93) { | } elsif ($marker == 0x93) { | |||
pop @$path; | pop @$path; | |||
$verbose and print $out "JPEG SOD\n"; | $verbose and print $out "JPEG SOD\n"; | |||
$success = 1; | $success = 1; | |||
next if $verbose > 2 or $htmlDump; | next if $verbose > 2 or $htmlDump; | |||
last; # all done parsing file | last; # all done parsing file | |||
} elsif (defined $markerLenBytes{$marker}) { | } elsif (defined $markerLenBytes{$marker}) { | |||
skipping to change at line 7012 | skipping to change at line 7039 | |||
$dumpType = 'InfiRay Data', | $dumpType = 'InfiRay Data', | |||
} elsif ($$segDataPt =~ /^\xff\xd8\xff\xdb/) { | } elsif ($$segDataPt =~ /^\xff\xd8\xff\xdb/) { | |||
$dumpType = 'PreviewImage'; # (Samsung, HP, BenQ) | $dumpType = 'PreviewImage'; # (Samsung, HP, BenQ) | |||
$preview = $$segDataPt; | $preview = $$segDataPt; | |||
} | } | |||
if ($preview and $nextMarker ne 0xe4) { # this preview continues in APP4 | if ($preview and $nextMarker ne 0xe4) { # this preview continues in APP4 | |||
$self->FoundTag('PreviewImage', $preview); | $self->FoundTag('PreviewImage', $preview); | |||
undef $preview; | undef $preview; | |||
} | } | |||
} elsif ($marker == 0xe4) { # APP4 (InfiRay, "SCALADO", FPXR, Pr eviewImage) | } elsif ($marker == 0xe4) { # APP4 (InfiRay, "SCALADO", FPXR, DJ I, PreviewImage) | |||
if ($$segDataPt =~ /^SCALADO\0/ and $length >= 16) { | if ($$segDataPt =~ /^SCALADO\0/ and $length >= 16) { | |||
$dumpType = 'SCALADO'; | $dumpType = 'SCALADO'; | |||
my ($num, $idx, $len) = unpack('x8n2N', $$segDataPt); | my ($num, $idx, $len) = unpack('x8n2N', $$segDataPt); | |||
# assume that the segments are in order and just concatinate the m | # assume that the segments are in order and just concatinate the m | |||
$scalado = '' unless defined $scalado; | $scalado = '' unless defined $scalado; | |||
$scalado .= substr($$segDataPt, 16); | $scalado .= substr($$segDataPt, 16); | |||
if ($idx == $num - 1) { | if ($idx == $num - 1) { | |||
if ($len != length $scalado) { | if ($len != length $scalado) { | |||
$self->Warn('Possibly corrupted APP4 SCALADO data', 1); | $self->Warn('Possibly corrupted APP4 SCALADO data', 1); | |||
} | } | |||
skipping to change at line 7043 | skipping to change at line 7070 | |||
$dumpType = 'FPXR'; | $dumpType = 'FPXR'; | |||
my $tagTablePtr = GetTagTable('Image::ExifTool::FlashPix::Main') ; | my $tagTablePtr = GetTagTable('Image::ExifTool::FlashPix::Main') ; | |||
# set flag if this is the last FPXR segment | # set flag if this is the last FPXR segment | |||
$dirInfo{LastFPXR} = not ($nextMarker==$marker and $$nextSegData Pt=~/^FPXR\0/), | $dirInfo{LastFPXR} = not ($nextMarker==$marker and $$nextSegData Pt=~/^FPXR\0/), | |||
$self->ProcessDirectory(\%dirInfo, $tagTablePtr); | $self->ProcessDirectory(\%dirInfo, $tagTablePtr); | |||
} elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^\xaa\x55\x12\x06 /) { | } elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^\xaa\x55\x12\x06 /) { | |||
$dumpType = 'DJI ThermalParams'; | $dumpType = 'DJI ThermalParams'; | |||
DirStart(\%dirInfo, 0, 0); | DirStart(\%dirInfo, 0, 0); | |||
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalPara ms'); | my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalPara ms'); | |||
$self->ProcessDirectory(\%dirInfo, $tagTablePtr); | $self->ProcessDirectory(\%dirInfo, $tagTablePtr); | |||
} elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^(.{32})?.{32}\x2 | ||||
c\x01\x20\0/s) { | ||||
$dumpType = 'DJI ThermalParams2'; | ||||
DirStart(\%dirInfo, $1 ? 32 : 0, 0); | ||||
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalPara | ||||
ms2'); | ||||
$self->ProcessDirectory(\%dirInfo, $tagTablePtr); | ||||
} elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^.{32}\xaa\x55\x3 | ||||
8\0/s) { | ||||
$dumpType = 'DJI ThermalParams3'; | ||||
DirStart(\%dirInfo, 32, 0); | ||||
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalPara | ||||
ms3'); | ||||
$self->ProcessDirectory(\%dirInfo, $tagTablePtr); | ||||
} elsif ($$self{HasIJPEG} and $length >= 120) { | } elsif ($$self{HasIJPEG} and $length >= 120) { | |||
$dumpType = 'InfiRay Factory'; | $dumpType = 'InfiRay Factory'; | |||
SetByteOrder('II'); | SetByteOrder('II'); | |||
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Factory '); | my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Factory '); | |||
$self->ProcessDirectory(\%dirInfo, $tagTablePtr); | $self->ProcessDirectory(\%dirInfo, $tagTablePtr); | |||
} elsif ($preview) { | } elsif ($preview) { | |||
# continued Samsung S1060 preview from APP3 | # continued Samsung S1060 preview from APP3 | |||
$dumpType = 'PreviewImage'; | $dumpType = 'PreviewImage'; | |||
$preview .= $$segDataPt; | $preview .= $$segDataPt; | |||
} | } | |||
skipping to change at line 7156 | skipping to change at line 7193 | |||
if ($htmlDump) { | if ($htmlDump) { | |||
$self->HDump($segPos-4, 4, 'APP7 header', "Data size: $lengt h bytes"); | $self->HDump($segPos-4, 4, 'APP7 header', "Data size: $lengt h bytes"); | |||
$self->HDump($segPos, $hdrLen, 'Huawei header', 'APP7 data t ype: Huawei'); | $self->HDump($segPos, $hdrLen, 'Huawei header', 'APP7 data t ype: Huawei'); | |||
$dumpEnd = $segPos + $length; | $dumpEnd = $segPos + $length; | |||
} | } | |||
$$self{SET_GROUP0} = 'APP7'; | $$self{SET_GROUP0} = 'APP7'; | |||
$$self{SET_GROUP1} = 'Huawei'; | $$self{SET_GROUP1} = 'Huawei'; | |||
$self->ProcessDirectory(\%dirInfo, $tagTablePtr); | $self->ProcessDirectory(\%dirInfo, $tagTablePtr); | |||
delete $$self{SET_GROUP0}; | delete $$self{SET_GROUP0}; | |||
delete $$self{SET_GROUP1}; | delete $$self{SET_GROUP1}; | |||
} elsif ($$segDataPt =~ /^DJI-DBG\0/) { | ||||
$dumpType = 'DJI Info'; | ||||
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::Info'); | ||||
DirStart(\%dirInfo, 8, 0); | ||||
$$self{SET_GROUP0} = 'APP7'; | ||||
$self->ProcessDirectory(\%dirInfo, $tagTablePtr); | ||||
delete $$self{SET_GROUP0}; | ||||
} elsif ($$segDataPt =~ /^\x1aQualcomm Camera Attributes/) { | } elsif ($$segDataPt =~ /^\x1aQualcomm Camera Attributes/) { | |||
# found in HP iPAQ_VoiceMessenger | # found in HP iPAQ_VoiceMessenger | |||
$dumpType = 'Qualcomm'; | $dumpType = 'Qualcomm'; | |||
my $tagTablePtr = GetTagTable('Image::ExifTool::Qualcomm::Main') ; | my $tagTablePtr = GetTagTable('Image::ExifTool::Qualcomm::Main') ; | |||
DirStart(\%dirInfo, 27); | DirStart(\%dirInfo, 27); | |||
$dirInfo{DirName} = 'Qualcomm'; | $dirInfo{DirName} = 'Qualcomm'; | |||
$self->ProcessDirectory(\%dirInfo, $tagTablePtr); | $self->ProcessDirectory(\%dirInfo, $tagTablePtr); | |||
} elsif ($$self{HasIJPEG} and $length >= 32) { | } elsif ($$self{HasIJPEG} and $length >= 32) { | |||
$dumpType = 'InfiRay OpMode'; | $dumpType = 'InfiRay OpMode'; | |||
SetByteOrder('II'); | SetByteOrder('II'); | |||
skipping to change at line 7684 | skipping to change at line 7728 | |||
# dump any other known trailer (eg. A100 RAW Data) | # dump any other known trailer (eg. A100 RAW Data) | |||
if ($$self{HTML_DUMP} and $$self{KnownTrailer}) { | if ($$self{HTML_DUMP} and $$self{KnownTrailer}) { | |||
my $known = $$self{KnownTrailer}; | my $known = $$self{KnownTrailer}; | |||
$raf->Seek(0, 2); | $raf->Seek(0, 2); | |||
my $len = $raf->Tell() - $$known{Start}; | my $len = $raf->Tell() - $$known{Start}; | |||
$len -= $$trailInfo{Offset} if $trailInfo; # account for other trailers | $len -= $$trailInfo{Offset} if $trailInfo; # account for other trailers | |||
$self->HDump($$known{Start}, $len, "[$$known{Name}]") if $len > 0; | $self->HDump($$known{Start}, $len, "[$$known{Name}]") if $len > 0; | |||
} | } | |||
} | } | |||
# update FileType if necessary now that we know more about the file | # update FileType if necessary now that we know more about the file | |||
if ($$self{DNGVersion} and $$self{VALUE}{FileType} !~ /^(DNG|GPR)$/) { | if ($$self{DNGVersion} and $$self{FileType} !~ /^(DNG|GPR)$/) { | |||
# override whatever FileType we set since we now know it is DNG | # override whatever FileType we set since we now know it is DNG | |||
$self->OverrideFileType($$self{TIFF_TYPE} = 'DNG'); | $self->OverrideFileType($$self{TIFF_TYPE} = 'DNG'); | |||
} | } | |||
if ($$self{TIFF_TYPE} eq 'TIFF') { | if ($$self{TIFF_TYPE} eq 'TIFF') { | |||
$self->FoundTag(PageCount => $$self{PageCount}) if $$self{MultiPage} ; | $self->FoundTag(PageCount => $$self{PageCount}) if $$self{MultiPage} ; | |||
} | } | |||
return 1; | return 1; | |||
} | } | |||
# | # | |||
# rewrite the image | # rewrite the image | |||
skipping to change at line 8570 | skipping to change at line 8614 | |||
#------------------------------------------------------------------------------ | #------------------------------------------------------------------------------ | |||
# Set the FileType and MIMEType tags | # Set the FileType and MIMEType tags | |||
# Inputs: 0) ExifTool object reference | # Inputs: 0) ExifTool object reference | |||
# 1) Optional file type (uses FILE_TYPE if not specified) | # 1) Optional file type (uses FILE_TYPE if not specified) | |||
# 2) Optional MIME type (uses our lookup if not specified) | # 2) Optional MIME type (uses our lookup if not specified) | |||
# 3) Optional recommended extension (converted to lower case; uses FileT ype if undef) | # 3) Optional recommended extension (converted to lower case; uses FileT ype if undef) | |||
# Notes: Will NOT set file type twice (subsequent calls ignored) | # Notes: Will NOT set file type twice (subsequent calls ignored) | |||
sub SetFileType($;$$$) | sub SetFileType($;$$$) | |||
{ | { | |||
my ($self, $fileType, $mimeType, $normExt) = @_; | my ($self, $fileType, $mimeType, $normExt) = @_; | |||
unless ($$self{VALUE}{FileType} and not $$self{DOC_NUM}) { | unless ($$self{FileType} and not $$self{DOC_NUM}) { | |||
my $baseType = $$self{FILE_TYPE}; | my $baseType = $$self{FILE_TYPE}; | |||
my $ext = $$self{FILE_EXT}; | my $ext = $$self{FILE_EXT}; | |||
$fileType or $fileType = $baseType; | $fileType or $fileType = $baseType; | |||
# handle sub-types which are identified by extension | # handle sub-types which are identified by extension | |||
if (defined $ext and $ext ne $fileType and not $$self{DOC_NUM}) { | if (defined $ext and $ext ne $fileType and not $$self{DOC_NUM}) { | |||
my ($f,$e) = @fileTypeLookup{$fileType,$ext}; | my ($f,$e) = @fileTypeLookup{$fileType,$ext}; | |||
if (ref $f eq 'ARRAY' and ref $e eq 'ARRAY' and $$f[0] eq $$e[0]) { | if (ref $f eq 'ARRAY' and ref $e eq 'ARRAY' and $$f[0] eq $$e[0]) { | |||
# make sure $fileType was a root type and not another sub-type | # make sure $fileType was a root type and not another sub-type | |||
$fileType = $ext if $$f[0] eq $fileType or not $fileTypeLookup{$ $f[0]}; | $fileType = $ext if $$f[0] eq $fileType or not $fileTypeLookup{$ $f[0]}; | |||
} | } | |||
} | } | |||
$mimeType or $mimeType = $mimeType{$fileType}; | $mimeType or $mimeType = $mimeType{$fileType}; | |||
# use base file type if necessary (except if 'TIFF', which is a special case) | # use base file type if necessary (except if 'TIFF', which is a special case) | |||
$mimeType = $mimeType{$baseType} unless $mimeType or $baseType eq 'TIFF' ; | $mimeType = $mimeType{$baseType} unless $mimeType or $baseType eq 'TIFF' ; | |||
unless (defined $normExt) { | unless (defined $normExt) { | |||
$normExt = $fileTypeExt{$fileType}; | $normExt = $fileTypeExt{$fileType}; | |||
$normExt = $fileType unless defined $normExt; | $normExt = $fileType unless defined $normExt; | |||
} | } | |||
$$self{FileType} = $fileType; | # ($$self{FileType} is the file type of the main document) | |||
$$self{FileType} = $fileType unless $$self{DOC_NUM}; | ||||
$self->FoundTag('FileType', $fileType); | $self->FoundTag('FileType', $fileType); | |||
$self->FoundTag('FileTypeExtension', uc $normExt); | $self->FoundTag('FileTypeExtension', uc $normExt); | |||
$self->FoundTag('MIMEType', $mimeType || 'application/unknown'); | $self->FoundTag('MIMEType', $mimeType || 'application/unknown'); | |||
} | } | |||
} | } | |||
#------------------------------------------------------------------------------ | #------------------------------------------------------------------------------ | |||
# Override the FileType and MIMEType tags | # Override the FileType and MIMEType tags | |||
# Inputs: 0) ExifTool object ref, 1) file type, 2) MIME type, 3) normal extensio n (lower case) | # Inputs: 0) ExifTool object ref, 1) file type, 2) MIME type, 3) normal extensio n (lower case) | |||
# Notes: does nothing if FileType was not previously defined (ie. when writing) | # Notes: does nothing if FileType was not previously defined (ie. when writing) | |||
End of changes. 17 change blocks. | ||||
12 lines changed or deleted | 70 lines changed or added |