diff --git a/bin/Changes b/bin/Changes index 492508e..73f4445 100644 --- a/bin/Changes +++ b/bin/Changes @@ -4,15 +4,40 @@ ExifTool Version History RSS feed: https://exiftool.org/rss.xml -Note: The most recent production release is Version 13.00. (Other versions are +Note: The most recent production release is Version 13.10. (Other versions are considered development releases, and are not uploaded to MetaCPAN.) +Dec. 20, 2024 - Version 13.10 (production release) + + - Added warnings for out-of-order entries in 'iinf' and 'ipma' boxes of HEIC + images + - Added support for date/time formatting codes %f and %z in the inverse + print conversion when writing tags + - Updated Geolocation databases from current geonames.org files + - Improved verbose output to show values stored with construction method 1 in + MP4-based files + - Enhanced the date/time timezone format specifier %z so that %:z returns the + time zone with a colon separator (eg. "-05:00") + - Fixed bug where the existing tag wasn't being removed when writing a new + value for an Unknown QuickTime UserData or ItemList tag + +Dec. 17, 2024 - Version 13.09 + + - Added a new QuickTime tag (thanks Matti) + - Added a missing format check on a few tags when writing + - Decode a couple of new ICC_Profile tags + - Patched HEIC writer so newly added XMP or EXIF refers to the 'tmap' item as + well as the primary item of an HDRGainMap image (since iPhone 15 and 16 do + it this way) + - Fixed compatibility issue where Apple Preview would no longer show the gain + map image after adding new XMP to an HEIC with an HDR gain map + Dec. 14, 2024 - Version 13.08 - Decode ShutterCount for Canon EOS R6 Mark II (thanks Agoston Kapitany) - Decode a few new Photoshop tags - Suppress all duplicate Warning tags and add count to end of message - - Changed format of bitmask keys in -list x output + - Changed format of bitmask keys in -listx output - Internal streamlining of LIGOGPSINFO decoding - Fixed issue where some tags were incorrectly shown as writable in -listx output diff --git a/bin/MANIFEST b/bin/MANIFEST index 08c552b..85fd018 100644 --- a/bin/MANIFEST +++ b/bin/MANIFEST @@ -937,6 +937,7 @@ t/Writer_58.out t/Writer_59.out t/Writer_6.out t/Writer_60.out +t/Writer_61.out t/Writer_7.out t/Writer_9.out t/XISF.t diff --git a/bin/META.json b/bin/META.json index 325b6d1..bd83260 100644 --- a/bin/META.json +++ b/bin/META.json @@ -50,5 +50,5 @@ } }, "release_status" : "stable", - "version" : "13.08" + "version" : "13.10" } diff --git a/bin/META.yml b/bin/META.yml index ead5de4..b66a2b2 100644 --- a/bin/META.yml +++ b/bin/META.yml @@ -31,4 +31,4 @@ recommends: Time::HiRes: '0' requires: perl: '5.004' -version: '13.08' +version: '13.10' diff --git a/bin/README b/bin/README index 62b2ffd..ae4f7b5 100644 --- a/bin/README +++ b/bin/README @@ -109,8 +109,8 @@ your home directory, then you would type the following commands in a terminal window to extract and run ExifTool: cd ~/Desktop - gzip -dc Image-ExifTool-13.08.tar.gz | tar -xf - - cd Image-ExifTool-13.08 + gzip -dc Image-ExifTool-13.10.tar.gz | tar -xf - + cd Image-ExifTool-13.10 ./exiftool t/images/ExifTool.jpg Note: These commands extract meta information from one of the test images. diff --git a/bin/exiftool b/bin/exiftool index 15041ba..1e58e5e 100755 --- a/bin/exiftool +++ b/bin/exiftool @@ -11,7 +11,7 @@ use strict; use warnings; require 5.004; -my $version = '13.08'; +my $version = '13.10'; # add our 'lib' directory to the include list BEFORE 'use Image::ExifTool' my $exePath; @@ -5644,16 +5644,29 @@ in the delimiter. Default is ','. Set the format for date/time tag values. The I string may contain formatting codes beginning with a percent character (C<%>) to represent the -various components of a date/time value. The specifics of the I syntax -are system dependent -- consult the C man page on your system for -details. The default format is equivalent to "%Y:%m:%d %H:%M:%S". This -option has no effect on date-only or time-only tags and ignores timezone -information if present. ExifTool adds a C<%f> format code to represent -fractional seconds, and supports an optional width to specify the number of -digits after the decimal point (eg. C<%3f> would give something like -C<.437>), and a minus sign to drop the decimal point (eg. C<%-3f> would give -C<437>). Only one B<-d> option may be used per command. Requires -POSIX::strptime or Time::Piece for the inversion conversion when writing. +various components of a date/time value. ExifTool implements 3 format codes +internally (see below), but other format codes are system dependent -- +consult the C man page on your system for details. The default +format is equivalent to "%Y:%m:%d %H:%M:%S". This option has no effect on +date-only or time-only tags. Requires POSIX::strptime or Time::Piece for +the inversion conversion when writing. Only one B<-d> option may be used +per command. + +Additional format codes implemented internally by ExifTool: + +1) C<%z> represents the time zone in "+/-HHMM" format. Adding a colon (ie. +C<%:z>) adds a colon separator (eg. "-05:00"). If the date/time value +doesn't contain a time zone then C<%z> gives the system time zone for the +specified date/time value. + +2) C<%f> represents fractional seconds, and supports an optional width to +specify the number of digits after the decimal point (eg. C<%3f> would give +something like ".437"). Adding a minus sign drops the decimal point (eg. +C<%-3f> would give "437"). + +3) C<%s> represents the number of seconds since 00:00 UTC Jan 1, 1970, +taking into account the specified time zone (or system time zone if not +specified). =item B<-D> (B<-decimal>) @@ -5913,7 +5926,7 @@ with this command: produces output like this: - -- Generated by ExifTool 13.08 -- + -- Generated by ExifTool 13.10 -- File: a.jpg - 2003:10:31 15:44:19 (f/5.6, 1/60s, ISO 100) File: b.jpg - 2006:05:23 11:57:38 diff --git a/bin/lib/Image/ExifTool.pm b/bin/lib/Image/ExifTool.pm index 4849597..4c7575e 100644 --- a/bin/lib/Image/ExifTool.pm +++ b/bin/lib/Image/ExifTool.pm @@ -29,7 +29,7 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes %jpegMarker %specialTags %fileTypeLookup $testLen $exeDir %static_vars $advFmtSelf); -$VERSION = '13.08'; +$VERSION = '13.10'; $RELEASE = ''; @ISA = qw(Exporter); %EXPORT_TAGS = ( @@ -6551,11 +6551,13 @@ sub ConvertDateTime($$) $fmt =~ s/(^|[^%])((%%)*)%-?\.?\d*f/$1$2$frac/g; } # parse %z and %s ourself (to handle time zones properly) - if ($fmt =~ /%[sz]/) { + if ($fmt =~ /%:?[sz]/) { # use system time zone unless otherwise specified $tz = TimeZoneString(\@a, TimeLocal(@a)) if not $tz and eval { require Time::Local }; # remove colon, setting to UTC if time zone is not numeric - $tz = ($tz and $tz=~/^([-+]\d{2}):(\d{2})$/) ? "$1$2" : '+0000'; + $tz = '+00:00' unless $tz and $tz=~/^[-+]\d{2}:\d{2}$/; + $fmt =~ s/(^|[^%])((%%)*)%:z/$1$2$tz/g; # convert '%:z' format codes + $tz =~ s/://; $fmt =~ s/(^|[^%])((%%)*)%z/$1$2$tz/g; # convert '%z' format codes if ($fmt =~ /%s/ and eval { require Time::Local }) { # calculate seconds since the Epoch, UTC @@ -8961,8 +8963,9 @@ sub GetTagInfo($$$;$$$) next; } } - # don't return Unknown tags unless that option is set (also see forum13716) - if ($$tagInfo{Unknown} and not $$options{Unknown} and not + # don't return Unknown tags unless that option is set or we are writing (also see forum13716) + if ($$tagInfo{Unknown} and not $$options{Unknown} and + (not $$self{IsWriting} or $$tagInfo{AddedUnknown}) and not ($$options{Verbose} or $$self{HTML_DUMP} or ($$options{Validate} and not $$tagInfo{AddedUnknown}))) { diff --git a/bin/lib/Image/ExifTool.pod b/bin/lib/Image/ExifTool.pod index 78b50a7..65b7394 100644 --- a/bin/lib/Image/ExifTool.pod +++ b/bin/lib/Image/ExifTool.pod @@ -613,8 +613,10 @@ different when copying tags with L. Format for printing date/time values. See C in the L package and L for details about the format string. If the date can not be converted, the value is left -unchanged unless the StrictDate option is set. Timezones are ignored. The -inverse conversion (ie. when calling L) is performed only if +unchanged unless the StrictDate option is set. ExifTool adds a few +additional format specifiers (C<%f>, C<%s> and C<%z>), see +L for more details. The inverse +conversion (ie. when calling L) is performed only if POSIX::strptime or Time::Piece is installed. The default setting of undef causes date/time values to remain in standard EXIF format (similar to a DateFormat of "%Y:%m:%d %H:%M:%S"). @@ -2559,39 +2561,39 @@ Ducky, EPPIM, EXE, EXIF, ExifIFD, ExifTool, FITS, FLAC, FLIR, File, Flash, FlashPix, Font, FotoStation, FujiFilm, FujiIFD, GE, GIF, GIMP, GM, GPS, GSpherical, Garmin, GeoTiff, GlobParamIFD, GoPro, GraphConv, H264, HP, HTC, HTML, HTML-dc, HTML-ncc, HTML-office, HTML-prod, HTML-vw96, HTTP-equiv, -ICC-chrm, ICC-clrt, ICC-header, ICC-meas, ICC-meta, ICC-view, ICC_Profile, -ICC_Profile#, ID3, ID3v1, ID3v1_Enh, ID3v2_2, ID3v2_3, ID3v2_4, IFD0, IFD1, -IPTC, IPTC#, ISO, ITC, InfiRay, Insta360, InteropIFD, ItemList, JFIF, JFXX, -JPEG, JPEG-HDR, JPS, JSON, JUMBF, JVC, Jpeg2000, KDC_IFD, Keys, Kodak, -KodakBordersIFD, KodakEffectsIFD, KodakIFD, KyoceraRaw, LIGO, LNK, Leaf, -LeafSubIFD, Leica, Lyrics3, Lytro, M-RAW, M2TS, MAC, MIE-Audio, MIE-Camera, -MIE-Canon, MIE-Doc, MIE-Extender, MIE-Flash, MIE-GPS, MIE-Geo, MIE-Image, -MIE-Lens, MIE-Main, MIE-MakerNotes, MIE-Meta, MIE-Orient, MIE-Preview, -MIE-Thumbnail, MIE-UTM, MIE-Unknown, MIE-Video, MIFF, MISB, MNG, MOBI, MOI, -MPC, MPEG, MPF0, MPImage, MS-DOC, MXF, MacOS, MakerNotes, MakerUnknown, -Matroska, MediaJukebox, Meta, MetaIFD, Microsoft, Minolta, MinoltaRaw, -Motorola, NITF, Nextbase, Nikon, NikonCapture, NikonCustom, NikonScan, -NikonSettings, NineEdits, Nintendo, Ocad, Ogg, Olympus, OpenEXR, Opus, PDF, -PICT, PNG, PNG-cICP, PNG-pHYs, PSP, Palm, Panasonic, PanasonicRaw, Parrot, -Pentax, PhaseOne, PhotoCD, PhotoMechanic, Photoshop, PictureInfo, -PostScript, PreviewIFD, PrintIM, ProfileIFD, Qualcomm, QuickTime, RAF, RAF2, -RIFF, RMETA, RSRC, RTF, Radiance, Rawzor, Real, Real-CONT, Real-MDPR, -Real-PROP, Real-RA3, Real-RA4, Real-RA5, Real-RJMD, Reconyx, Red, Ricoh, -SEAL, SPIFF, SR2, SR2DataIFD, SR2SubIFD, SRF#, SVG, Samsung, Sanyo, Scalado, -Sigma, SigmaRaw, Sony, SonyIDC, Stim, SubIFD, System, Theora, Torrent, -Track#, UserData, VCalendar, VCard, VNote, Version0, Vorbis, WTV, XML, XMP, -XMP-DICOM, XMP-Device, XMP-GAudio, XMP-GCamera, XMP-GContainer, -XMP-GCreations, XMP-GDepth, XMP-GFocus, XMP-GImage, XMP-GPano, -XMP-GSpherical, XMP-LImage, XMP-MP, XMP-MP1, XMP-PixelLive, XMP-aas, -XMP-acdsee, XMP-acdsee-rs, XMP-album, XMP-apple-fi, XMP-ast, XMP-aux, -XMP-cc, XMP-cell, XMP-crd, XMP-creatorAtom, XMP-crs, XMP-dc, XMP-dex, -XMP-digiKam, XMP-drone-dji, XMP-dwc, XMP-et, XMP-exif, XMP-exifEX, -XMP-expressionmedia, XMP-extensis, XMP-fpv, XMP-getty, XMP-hdr, XMP-hdrgm, -XMP-ics, XMP-iptcCore, XMP-iptcExt, XMP-lr, XMP-mediapro, XMP-microsoft, -XMP-mwg-coll, XMP-mwg-kw, XMP-mwg-rs, XMP-nine, XMP-panorama, XMP-pdf, -XMP-pdfx, XMP-photomech, XMP-photoshop, XMP-plus, XMP-pmi, XMP-prism, -XMP-prl, XMP-prm, XMP-pur, XMP-rdf, XMP-sdc, XMP-swf, XMP-tiff, XMP-x, -XMP-xmp, XMP-xmpBJ, XMP-xmpDM, XMP-xmpDSA, XMP-xmpMM, XMP-xmpNote, +ICC-chrm, ICC-cicp, ICC-clrt, ICC-header, ICC-meas, ICC-meta, ICC-view, +ICC_Profile, ICC_Profile#, ID3, ID3v1, ID3v1_Enh, ID3v2_2, ID3v2_3, ID3v2_4, +IFD0, IFD1, IPTC, IPTC#, ISO, ITC, InfiRay, Insta360, InteropIFD, ItemList, +JFIF, JFXX, JPEG, JPEG-HDR, JPS, JSON, JUMBF, JVC, Jpeg2000, KDC_IFD, Keys, +Kodak, KodakBordersIFD, KodakEffectsIFD, KodakIFD, KyoceraRaw, LIGO, LNK, +Leaf, LeafSubIFD, Leica, Lyrics3, Lytro, M-RAW, M2TS, MAC, MIE-Audio, +MIE-Camera, MIE-Canon, MIE-Doc, MIE-Extender, MIE-Flash, MIE-GPS, MIE-Geo, +MIE-Image, MIE-Lens, MIE-Main, MIE-MakerNotes, MIE-Meta, MIE-Orient, +MIE-Preview, MIE-Thumbnail, MIE-UTM, MIE-Unknown, MIE-Video, MIFF, MISB, +MNG, MOBI, MOI, MPC, MPEG, MPF0, MPImage, MS-DOC, MXF, MacOS, MakerNotes, +MakerUnknown, Matroska, MediaJukebox, Meta, MetaIFD, Microsoft, Minolta, +MinoltaRaw, Motorola, NITF, Nextbase, Nikon, NikonCapture, NikonCustom, +NikonScan, NikonSettings, NineEdits, Nintendo, Ocad, Ogg, Olympus, OpenEXR, +Opus, PDF, PICT, PNG, PNG-cICP, PNG-pHYs, PSP, Palm, Panasonic, +PanasonicRaw, Parrot, Pentax, PhaseOne, PhotoCD, PhotoMechanic, Photoshop, +PictureInfo, PostScript, PreviewIFD, PrintIM, ProfileIFD, Qualcomm, +QuickTime, RAF, RAF2, RIFF, RMETA, RSRC, RTF, Radiance, Rawzor, Real, +Real-CONT, Real-MDPR, Real-PROP, Real-RA3, Real-RA4, Real-RA5, Real-RJMD, +Reconyx, Red, Ricoh, SEAL, SPIFF, SR2, SR2DataIFD, SR2SubIFD, SRF#, SVG, +Samsung, Sanyo, Scalado, Sigma, SigmaRaw, Sony, SonyIDC, Stim, SubIFD, +System, Theora, Torrent, Track#, UserData, VCalendar, VCard, VNote, +Version0, Vorbis, WTV, XML, XMP, XMP-DICOM, XMP-Device, XMP-GAudio, +XMP-GCamera, XMP-GContainer, XMP-GCreations, XMP-GDepth, XMP-GFocus, +XMP-GImage, XMP-GPano, XMP-GSpherical, XMP-LImage, XMP-MP, XMP-MP1, +XMP-PixelLive, XMP-aas, XMP-acdsee, XMP-acdsee-rs, XMP-album, XMP-apple-fi, +XMP-ast, XMP-aux, XMP-cc, XMP-cell, XMP-crd, XMP-creatorAtom, XMP-crs, +XMP-dc, XMP-dex, XMP-digiKam, XMP-drone-dji, XMP-dwc, XMP-et, XMP-exif, +XMP-exifEX, XMP-expressionmedia, XMP-extensis, XMP-fpv, XMP-getty, XMP-hdr, +XMP-hdrgm, XMP-ics, XMP-iptcCore, XMP-iptcExt, XMP-lr, XMP-mediapro, +XMP-microsoft, XMP-mwg-coll, XMP-mwg-kw, XMP-mwg-rs, XMP-nine, XMP-panorama, +XMP-pdf, XMP-pdfx, XMP-photomech, XMP-photoshop, XMP-plus, XMP-pmi, +XMP-prism, XMP-prl, XMP-prm, XMP-pur, XMP-rdf, XMP-sdc, XMP-swf, XMP-tiff, +XMP-x, XMP-xmp, XMP-xmpBJ, XMP-xmpDM, XMP-xmpDSA, XMP-xmpMM, XMP-xmpNote, XMP-xmpPLUS, XMP-xmpRights, XMP-xmpTPg, ZIP, iTunes =item Family 2 (Category): @@ -2832,6 +2834,10 @@ for the system. In Windows this also has the effect of activating Unicode filename support via the special Windows wide-character i/o routines if Win32API::File is available. +Note that setting the L or L option +causes L to default to 'UTF8' in Windows if not defined, +and L is set by default in ExifTool 13.07 and later. + =item Internal Character Sets: The encodings used to store strings in the various metadata formats. These diff --git a/bin/lib/Image/ExifTool/Apple.pm b/bin/lib/Image/ExifTool/Apple.pm index 74e0bdd..fc11678 100644 --- a/bin/lib/Image/ExifTool/Apple.pm +++ b/bin/lib/Image/ExifTool/Apple.pm @@ -16,7 +16,7 @@ use vars qw($VERSION); use Image::ExifTool::Exif; use Image::ExifTool::PLIST; -$VERSION = '1.13'; +$VERSION = '1.14'; sub ConvertPLIST($$); @@ -291,12 +291,12 @@ sub ConvertPLIST($$); # 0x0047 - (LeaderFollowerAutoFocusLeaderDepth, ref 2) # 0x0048 - (LeaderFollowerAutoFocusLeaderFocusMethod, ref 2) # 0x0049 - (LeaderFollowerAutoFocusLeaderConfidence, ref 2) - # 0x004A - (LeaderFollowerAutoFocusLeaderROIType, ref 2) + # 0x004a - (LeaderFollowerAutoFocusLeaderROIType, ref 2) # 0x004a - 2=back normal, 4=back wide angle, 5=front (ref PH) - # 0x004B - (ZeroShutterLagFailureReason, ref 2) - # 0x004C - (TimeOfFlightAssistedAutoFocusEstimatorMSPMeasuredDepth, ref 2) - # 0x004D - (TimeOfFlightAssistedAutoFocusEstimatorMSPSensorConfidence, ref 2) - # 0x004E - (Camera, ref 2) + # 0x004b - (ZeroShutterLagFailureReason, ref 2) + # 0x004c - (TimeOfFlightAssistedAutoFocusEstimatorMSPMeasuredDepth, ref 2) + # 0x004d - (TimeOfFlightAssistedAutoFocusEstimatorMSPSensorConfidence, ref 2) + # 0x004e - (Camera, ref 2) 0x004e => { Name => 'Apple_0x004e', Unknown => 1, @@ -358,7 +358,8 @@ Image::ExifTool::AddCompositeTags('Image::ExifTool::Apple'); sub ConvertPLIST($$) { my ($val, $et) = @_; - my $dirInfo = { DataPt => \$val }; + my $dirInfo = { DataPt => \$val, NoVerboseDir => 1 }; + my $oldOrder = $et->GetByteOrder(); require Image::ExifTool::PLIST; Image::ExifTool::PLIST::ProcessBinaryPLIST($et, $dirInfo); $val = $$dirInfo{Value}; @@ -366,6 +367,7 @@ sub ConvertPLIST($$) require 'Image/ExifTool/XMPStruct.pl'; $val = Image::ExifTool::XMP::SerializeStruct($et, $val); } + $et->SetByteOrder($oldOrder); return $val; } diff --git a/bin/lib/Image/ExifTool/BuildTagLookup.pm b/bin/lib/Image/ExifTool/BuildTagLookup.pm index d86188a..c1e9e52 100644 --- a/bin/lib/Image/ExifTool/BuildTagLookup.pm +++ b/bin/lib/Image/ExifTool/BuildTagLookup.pm @@ -866,6 +866,11 @@ sub new } $noID = 1 if $isXMP or $short =~ /^(Shortcuts|ASF.*)$/ or $$vars{NO_ID}; $hexID = $$vars{HEX_ID}; + if ($$table{WRITE_PROC} and $$table{WRITE_PROC} eq \&Image::ExifTool::WriteBinaryData + and not $$table{CHECK_PROC}) + { + warn("Binary table $tableName doesn't have a CHECK_PROC\n"); + } my $processBinaryData = ($$table{PROCESS_PROC} and ( $$table{PROCESS_PROC} eq \&Image::ExifTool::ProcessBinaryData or $$table{PROCESS_PROC} eq \&Image::ExifTool::Nikon::ProcessNikonEncrypted or @@ -1004,6 +1009,9 @@ TagID: foreach $tagID (@keys) { if ($writable and not ($$table{WRITE_PROC} or $tableName =~ /Shortcuts/ or $writable eq '2')) { undef $writable; } + #if ($writable and $$tagInfo{Unknown} and $$table{GROUPS}{0} ne 'MakerNotes') { + # warn "Warning: Writable Unknown tag - $short $name\n", + #} # validate some characteristics of obvious date/time tags my @g = $et->GetGroup($tagInfo); if ($$tagInfo{List} and $g[2] eq 'Time' and $writable and not $$tagInfo{Protected} and diff --git a/bin/lib/Image/ExifTool/Geolocation.dat b/bin/lib/Image/ExifTool/Geolocation.dat index 7cdc741..8276718 100644 Binary files a/bin/lib/Image/ExifTool/Geolocation.dat and b/bin/lib/Image/ExifTool/Geolocation.dat differ diff --git a/bin/lib/Image/ExifTool/ICC_Profile.pm b/bin/lib/Image/ExifTool/ICC_Profile.pm index 9b6719a..c0b683c 100644 --- a/bin/lib/Image/ExifTool/ICC_Profile.pm +++ b/bin/lib/Image/ExifTool/ICC_Profile.pm @@ -12,6 +12,7 @@ # 5) http://www.color.org/icc_specs2.xalter (approved revisions, 2010-07-16) # 6) Eef Vreeland private communication # 7) https://color.org/specification/ICC.2-2019.pdf +# 8) https://www.color.org/specification/ICC.1-2022-05.pdf # # Notes: The ICC profile information is different: the format of each # tag is embedded in the information instead of in the directory @@ -25,7 +26,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.40'; +$VERSION = '1.41'; sub ProcessICC($$); sub ProcessICC_Profile($$$); @@ -367,6 +368,7 @@ my %manuSig = ( #6 Groups => { 2 => 'Time' }, PrintConv => '$self->ConvertDateTime($val)', }, + targ => { Name => 'CharTarget', ValueConv => '$val=~s/\0.*//; length $val > 128 ? \$val : $val', @@ -493,6 +495,10 @@ my %manuSig = ( #6 }, }, ciis => 'ColorimetricIntentImageState', #5 + cicp => { #8 (Coding-independent Code Points) + Name => 'ColorRepresentation', + SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::ColorRep' }, + }, scoe => 'SceneColorimetryEstimates', #5 sape => 'SceneAppearanceEstimates', #5 fpce => 'FocalPlaneColorimetryEstimates', #5 @@ -628,6 +634,7 @@ my %manuSig = ( #6 s2cp => 'StandardToCustomPcc', smap => 'SurfaceMap', # smwp ? (seen in some v5 samples [was a mistake in sample production]) + hdgm => { Name => 'HDGainMapInfo', Binary => 1 }, #PH # the following entry represents the ICC profile header, and doesn't # exist as a tag in the directory. It is only in this table to provide @@ -747,6 +754,78 @@ my %manuSig = ( #6 }, ); +# Coding-independent code points (cicp) definition +# (NOTE: conversions are the same as Image::ExifTool::QuickTime::ColorRep tags) +%Image::ExifTool::ICC_Profile::ColorRep = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-cicp', 2 => 'Image' }, + 8 => { + Name => 'ColorPrimaries', + PrintConv => { + 1 => 'BT.709', + 2 => 'Unspecified', + 4 => 'BT.470 System M (historical)', + 5 => 'BT.470 System B, G (historical)', + 6 => 'BT.601', + 7 => 'SMPTE 240', + 8 => 'Generic film (color filters using illuminant C)', + 9 => 'BT.2020, BT.2100', + 10 => 'SMPTE 428 (CIE 1931 XYZ)', #forum14766 + 11 => 'SMPTE RP 431-2', + 12 => 'SMPTE EG 432-1', + 22 => 'EBU Tech. 3213-E', + }, + }, + 9 => { + Name => 'TransferCharacteristics', + PrintConv => { + 0 => 'For future use (0)', + 1 => 'BT.709', + 2 => 'Unspecified', + 3 => 'For future use (3)', + 4 => 'BT.470 System M (historical)', # Gamma 2.2? (ref forum14960) + 5 => 'BT.470 System B, G (historical)', # Gamma 2.8? (ref forum14960) + 6 => 'BT.601', + 7 => 'SMPTE 240 M', + 8 => 'Linear', + 9 => 'Logarithmic (100 : 1 range)', + 10 => 'Logarithmic (100 * Sqrt(10) : 1 range)', + 11 => 'IEC 61966-2-4', + 12 => 'BT.1361', + 13 => 'sRGB or sYCC', + 14 => 'BT.2020 10-bit systems', + 15 => 'BT.2020 12-bit systems', + 16 => 'SMPTE ST 2084, ITU BT.2100 PQ', + 17 => 'SMPTE ST 428', + 18 => 'BT.2100 HLG, ARIB STD-B67', + }, + }, + 10 => { + Name => 'MatrixCoefficients', + PrintConv => { + 0 => 'Identity matrix', + 1 => 'BT.709', + 2 => 'Unspecified', + 3 => 'For future use (3)', + 4 => 'US FCC 73.628', + 5 => 'BT.470 System B, G (historical)', + 6 => 'BT.601', + 7 => 'SMPTE 240 M', + 8 => 'YCgCo', + 9 => 'BT.2020 non-constant luminance, BT.2100 YCbCr', + 10 => 'BT.2020 constant luminance', + 11 => 'SMPTE ST 2085 YDzDx', + 12 => 'Chromaticity-derived non-constant luminance', + 13 => 'Chromaticity-derived constant luminance', + 14 => 'BT.2100 ICtCp', + }, + }, + 11 => { + Name => 'VideoFullRangeFlag', + PrintConv => { 0 => 'Limited', 1 => 'Full' }, + }, +); + # viewingConditionsType (view) definition %Image::ExifTool::ICC_Profile::ViewingConditions = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, diff --git a/bin/lib/Image/ExifTool/Jpeg2000.pm b/bin/lib/Image/ExifTool/Jpeg2000.pm index 8b19bad..d7a8306 100644 --- a/bin/lib/Image/ExifTool/Jpeg2000.pm +++ b/bin/lib/Image/ExifTool/Jpeg2000.pm @@ -16,7 +16,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.42'; +$VERSION = '1.43'; sub ProcessJpeg2000Box($$$); sub ProcessJUMD($$$); @@ -631,6 +631,7 @@ my %j2cMarker = ( %Image::ExifTool::Jpeg2000::ColorSpec = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, WRITE_PROC => \&Image::ExifTool::WriteBinaryData, # (we don't actually call this) + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, GROUPS => { 2 => 'Image' }, FORMAT => 'int8s', WRITABLE => 1, diff --git a/bin/lib/Image/ExifTool/PLIST.pm b/bin/lib/Image/ExifTool/PLIST.pm index 0643f00..070caad 100644 --- a/bin/lib/Image/ExifTool/PLIST.pm +++ b/bin/lib/Image/ExifTool/PLIST.pm @@ -21,7 +21,7 @@ use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::XMP; use Image::ExifTool::GPS; -$VERSION = '1.12'; +$VERSION = '1.13'; sub ExtractObject($$;$); sub Get24u($$); @@ -344,7 +344,7 @@ sub ProcessBinaryPLIST($$;$) my ($i, $buff, @table); my $dataPt = $$dirInfo{DataPt}; - $et->VerboseDir('Binary PLIST'); + $et->VerboseDir('Binary PLIST') unless $$dirInfo{NoVerboseDir}; SetByteOrder('MM'); if ($dataPt) { diff --git a/bin/lib/Image/ExifTool/PNG.pm b/bin/lib/Image/ExifTool/PNG.pm index a0a4e8e..49f8893 100644 --- a/bin/lib/Image/ExifTool/PNG.pm +++ b/bin/lib/Image/ExifTool/PNG.pm @@ -36,7 +36,7 @@ use strict; use vars qw($VERSION $AUTOLOAD %stdCase); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.69'; +$VERSION = '1.70'; sub ProcessPNG_tEXt($$$); sub ProcessPNG_iTXt($$$); @@ -435,6 +435,7 @@ my %noLeapFrog = ( SAVE => 1, SEEK => 1, IHDR => 1, JHDR => 1, IEND => 1, MEND = %Image::ExifTool::PNG::PhysicalPixel = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, WRITE_PROC => \&Image::ExifTool::WriteBinaryData, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, WRITABLE => 1, GROUPS => { 1 => 'PNG-pHYs', 2 => 'Image' }, WRITE_GROUP => 'PNG-pHYs', diff --git a/bin/lib/Image/ExifTool/Photoshop.pm b/bin/lib/Image/ExifTool/Photoshop.pm index 203c4f3..451dbca 100644 --- a/bin/lib/Image/ExifTool/Photoshop.pm +++ b/bin/lib/Image/ExifTool/Photoshop.pm @@ -362,6 +362,7 @@ my %unicodeString = ( PROCESS_PROC => \&ProcessChannelOptions, VARS => { IS_BINARY => 1 }, GROUPS => { 2 => 'Image' }, + NOTES => 'These tags relate only to the appearance of a channel.', 0 => { Name => 'ChannelColorSpace', Format => 'int16u', diff --git a/bin/lib/Image/ExifTool/QuickTime.pm b/bin/lib/Image/ExifTool/QuickTime.pm index 689bad9..29b7fae 100644 --- a/bin/lib/Image/ExifTool/QuickTime.pm +++ b/bin/lib/Image/ExifTool/QuickTime.pm @@ -48,7 +48,7 @@ use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; use Image::ExifTool::GPS; -$VERSION = '3.05'; +$VERSION = '3.07'; sub ProcessMOV($$;$); sub ProcessKeys($$$); @@ -2222,8 +2222,8 @@ my %userDefined = ( _cx_ => { Name => 'CX', Format => 'rational64s', Unknown => 1 }, _cy_ => { Name => 'CY', Format => 'rational64s', Unknown => 1 }, rads => { Name => 'Rads', Format => 'rational64s', Unknown => 1 }, - lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess) - Lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess) + lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess, Kodak proprietary) + Lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess, Kodak proprietary) pose => { Name => 'pose', SubDirectory => { TagTable => 'Image::ExifTool::Kodak::pose' } }, # AMBA => Ambarella AVC atom (unknown data written by Kodak Playsport video cam) # tmlp - 1 byte: 0 (PixPro SP360/4KVR360) @@ -2822,7 +2822,7 @@ my %userDefined = ( }, iinf => [{ Name => 'ItemInformation', - Condition => '$$valPt =~ /^\0/', # (check for version 0) + Condition => '$$self{LastItemID} = -1; $$valPt =~ /^\0/', # (check for version 0) SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemInfo', Start => 6, # (4-byte version/flags + 2-byte count) @@ -2894,6 +2894,17 @@ my %userDefined = ( %unknownInfo, }, ], + grpl => { + Name => 'Unknown_grpl', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::grpl' }, + }, +); + +# unknown grpl container +%Image::ExifTool::QuickTime::grpl = ( + PROCESS_PROC => \&ProcessMOV, + GROUPS => { 2 => 'Video' }, + # altr - seen "00 00 00 00 00 00 00 41 00 00 00 02 00 00 00 42 00 00 00 2e" ); # additional metadata container (ref ISO14496-12:2015) @@ -3038,6 +3049,7 @@ my %userDefined = ( ); # ref https://aomediacodec.github.io/av1-spec/av1-spec.pdf +# (NOTE: conversions are the same as Image::ExifTool::ICC_Profile::ColorRep tags) %Image::ExifTool::QuickTime::ColorRep = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, GROUPS => { 2 => 'Video' }, @@ -3321,7 +3333,13 @@ my %userDefined = ( the associations between items in the file. This information is used by ExifTool, but these entries are not extracted as tags. }, - dimg => { Name => 'DerivedImageRef', RawConv => 'undef' }, + dimg => { + Name => 'DerivedImageRef', + # also parse these for the ID of the primary 'tmap' item + # (tone-mapped image in HDRGainMap HEIC by iPhone 15 and 16) + RawConv => \&ParseContentDescribes, + WriteHook => \&ParseContentDescribes, + }, thmb => { Name => 'ThumbnailRef', RawConv => 'undef' }, auxl => { Name => 'AuxiliaryImageRef', RawConv => 'undef' }, cdsc => { @@ -3339,7 +3357,8 @@ my %userDefined = ( # hvc1 - HEVC image # lhv1 - L-HEVC image # infe - ItemInformationEntry - # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,hvt1(tile image) + # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,tmap,hvt1(tile image) + # ('tmap' has something to do with the new gainmap written by iPhone 15 and 16) infe => { Name => 'ItemInfoEntry', RawConv => \&ParseItemInfoEntry, @@ -6569,7 +6588,7 @@ my %userDefined = ( PROCESS_PROC => \&ProcessKeys, WRITE_PROC => \&WriteKeys, CHECK_PROC => \&CheckQTValue, - VARS => { LONG_TAGS => 8 }, + VARS => { LONG_TAGS => 9 }, WRITABLE => 1, # (not PREFERRED when writing) GROUPS => { 1 => 'Keys' }, @@ -6767,6 +6786,7 @@ my %userDefined = ( ValueConv => 'unpack("N", $val)', Writable => 0, # (don't make this writable because it is found in timed metadata) }, + 'full-frame-rate-playback-intent' => 'FullFrameRatePlaybackIntent', #forum16824 # # seen in Apple ProRes RAW file # @@ -8787,6 +8807,7 @@ sub PrintableTagID($;$) # ContentType - mime type of item # ContentEncoding - item encoding # URI - URI of a 'uri '-type item +# infe - raw data for 'infe' box (when writing only) [retracted] # ipma: # Association - list of associated properties in the ipco container # Essential - list of "essential" flags for the associated properties @@ -8937,10 +8958,18 @@ sub ParseItemInfoEntry($$) $$items{$id}{URI} = GetString(\$val, $pos); } } + #[retracted] # save raw infe box when writing in case we need to sort items later + #[retracted] $$items{$id}{infe} = pack('N', length($val)+8) . 'infe' . $val if $$et{IsWriting}; $et->VPrint(1, "$$et{INDENT} Item $id: Type=", $$items{$id}{Type} || '', ' Name=', $$items{$id}{Name} || '', ' ContentType=', $$items{$id}{ContentType} || '', + ($$et{PrimaryItem} and $$et{PrimaryItem} == $id) ? ' (PrimaryItem)' : '', "\n") if $verbose > 1; + unless ($id > $$et{LastItemID}) { + $et->Warn('Item info entries are out of order'); #[retracted] unless $$et{IsWriting}; + #[retracted] $$et{ItemsNotSorted} = 1; # set flag indicating the items weren't sorted + } + $$et{LastItemID} = $id; return undef; } @@ -8961,6 +8990,7 @@ sub ParseItemPropAssoc($$) my $flg = Get32u(\$val, 0); my $num = Get32u(\$val, 4); my $pos = 8; + my $lastID = -1; for ($i=0; $i<$num; ++$i) { if ($ver == 0) { return undef if $pos + 3 > $len; @@ -8993,6 +9023,9 @@ sub ParseItemPropAssoc($$) $$items{$id}{Association} = \@association; $$items{$id}{Essential} = \@essential; $et->VPrint(1, "$$et{INDENT} Item $id properties: @association\n") if $verbose > 1; + # (according to ISO/IEC 23008-12, these entries must be sorted by item ID) + $et->Warn('Item property association entries are out of order') unless $id > $lastID; + $lastID = $id; } return undef; } @@ -9039,7 +9072,10 @@ sub HandleItemInfo($) } } $warn = "Can't currently decode protected $type metadata" if $$item{ProtectionIndex}; - $warn = "Can't currently extract $type with construction method $$item{ConstructionMethod}" if $$item{ConstructionMethod}; + # Note: In HEIC's, these seem to indicate data in 'idat' instead of 'mdat' + my $constMeth = $$item{ConstructionMethod} || 0; + $warn = "Can't currently extract $type with construction method $constMeth" if $constMeth > 1; + $warn = "No 'idat' for $type object with construction method 1" if $constMeth == 1 and not $$et{MediaDataInfo}; $et->Warn($warn) if $warn and $name; $warn = 'Not this file' if $$item{DataReferenceIndex}; # (can only extract from "this file") unless (($$item{Extents} and @{$$item{Extents}}) or $warn) { @@ -9050,7 +9086,7 @@ sub HandleItemInfo($) $et->VPrint(0, "$$et{INDENT} [not extracted] ($warn)\n") if $verbose > 2; next; } - my $base = $$item{BaseOffset} || 0; + my $base = ($$item{BaseOffset} || 0) + ($constMeth ? $$et{MediaDataInfo}[0] : 0); if ($verbose > 2) { # do verbose hex dump my $len = 0; @@ -9189,6 +9225,7 @@ sub HandleItemInfo($) delete $$et{DOC_NUM}; } delete $$et{ItemInfo}; + delete $$et{MediaDataInfo}; } #------------------------------------------------------------------------------ @@ -9771,8 +9808,10 @@ sub ProcessMOV($$;$) # save required tag sizes if ($$tagTablePtr{"$tag-size"}) { $et->HandleTag($tagTablePtr, "$tag-size", $size); - $et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()) if $$tagTablePtr{"$tag-offset"}; + $et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()+$dirBase) if $$tagTablePtr{"$tag-offset"}; } + # save position/size of 'idat' + $$et{MediaDataInfo} = [ $raf->Tell() + $dirBase, $size ] if $tag eq 'idat'; # stop processing at mdat/idat if -fast2 is used last if $fast > 1 and ($tag eq 'mdat' or ($tag eq 'idat' and $$et{FileType} ne 'HEIC')); # load values only if associated with a tag (or verbose) and not too big diff --git a/bin/lib/Image/ExifTool/TagLookup.pm b/bin/lib/Image/ExifTool/TagLookup.pm index 930c04c..fe2ba9b 100644 --- a/bin/lib/Image/ExifTool/TagLookup.pm +++ b/bin/lib/Image/ExifTool/TagLookup.pm @@ -3261,6 +3261,7 @@ my %tagLookup = ( 'fujiflashmode' => { 133 => 0x1010 }, 'fujimodel' => { 133 => 0x1447 }, 'fujimodel2' => { 133 => 0x1448 }, + 'fullframerateplaybackintent' => { 409 => 'full-frame-rate-playback-intent' }, 'fullhdhighspeedrec' => { 133 => 0x3824 }, 'fullimagesize' => { 456 => 0xb02b }, 'fullpanoheightpixels' => { 507 => 'FullPanoHeightPixels', 508 => 'FullPanoHeightPixels' }, @@ -9862,6 +9863,7 @@ my %tagExists = ( 'hasxfa' => 1, 'hcusage' => 1, 'hdcontent' => 1, + 'hdgainmapinfo' => 1, 'hdmibitdepth' => 1, 'hdmiexternalrecorder' => 1, 'hdmioutputhdr' => 1, @@ -12813,6 +12815,7 @@ my %tagExists = ( 'unknown02' => 1, 'unknown03' => 1, 'unknown_cndb' => 1, + 'unknown_grpl' => 1, 'unknown_h' => 1, 'unknown_m' => 1, 'unknown_slmt' => 1, diff --git a/bin/lib/Image/ExifTool/TagNames.pod b/bin/lib/Image/ExifTool/TagNames.pod index 8084370..f97ccdc 100644 --- a/bin/lib/Image/ExifTool/TagNames.pod +++ b/bin/lib/Image/ExifTool/TagNames.pod @@ -12,7 +12,7 @@ meta information extracted from or written to a file. =head1 TAG TABLES The tables listed below give the names of all tags recognized by ExifTool. -They contain a total of 28218 tags, with 17514 unique tag names. +They contain a total of 28224 tags, with 17515 unique tag names. B, B or B is given in the first column of each table. A B is the computer-readable equivalent of a tag name, and @@ -8643,6 +8643,7 @@ specification. 'cept' ColorEncodingParams no 'chad' ChromaticAdaptation no 'chrm' Chromaticity ICC_Profile Chromaticity + 'cicp' ColorRepresentation ICC_Profile ColorRep 'ciis' ColorimetricIntentImageState no 'clio' ColorantInfoOut no 'cloo' ColorantOrderOut no @@ -8681,6 +8682,7 @@ specification. 'gdb1' GamutBoundaryDescription1 no 'gdb2' GamutBoundaryDescription2 no 'gdb3' GamutBoundaryDescription3 no + 'hdgm' HDGainMapInfo no 'kTRC' GrayTRC no 'lumi' Luminance no 'mcta' MultiplexTypeArray no @@ -8762,6 +8764,15 @@ specification. 28 ChromaticityChannel3 no 36 ChromaticityChannel4 no +=head3 ICC_Profile ColorRep Tags + + Index1 Tag Name Writable + ------ -------- -------- + 8 ColorPrimaries no + 9 TransferCharacteristics no + 10 MatrixCoefficients no + 11 VideoFullRangeFlag no + =head3 ICC_Profile ColorantTable Tags Index1 Tag Name Writable @@ -8968,6 +8979,8 @@ access to this information. =head3 Photoshop ChannelOptions Tags +These tags relate only to the appearance of a channel. + Index1 Tag Name Writable ------ -------- -------- 0 ChannelColorSpace no @@ -30273,6 +30286,8 @@ changed via the config file. 'director' Director yes 'displayname' DisplayName yes 'encoder' Encoder yes + 'full-frame-rate-playback-intent' + FullFrameRatePlaybackIntent yes 'genre' Genre yes 'information' Information yes 'keywords' Keywords yes @@ -30405,6 +30420,7 @@ Tags found in Pittasoft Blackvue dashcam "free" data. 'bxml' BinaryXML? no 'dinf' DataInfo QuickTime DataInfo 'free' Free? no + 'grpl' Unknown_grpl QuickTime grpl 'hdlr' Handler QuickTime Handler 'idat' MetaImageSize no 'iinf' ItemInformation QuickTime ItemInfo @@ -30439,6 +30455,12 @@ MP4 data reference box. 'url ' URL no 'urn ' URN no +=head3 QuickTime grpl Tags + + Tag ID Tag Name Writable + ------ -------- -------- + [no tags known] + =head3 QuickTime Handler Tags Index1 Tag Name Writable diff --git a/bin/lib/Image/ExifTool/WriteQuickTime.pl b/bin/lib/Image/ExifTool/WriteQuickTime.pl index 267b7de..ead12ec 100644 --- a/bin/lib/Image/ExifTool/WriteQuickTime.pl +++ b/bin/lib/Image/ExifTool/WriteQuickTime.pl @@ -482,23 +482,26 @@ ($$$) sub WriteItemInfo($$$) { my ($et, $dirInfo, $outfile) = @_; - my $boxPos = $$dirInfo{BoxPos}; # hash of [length,position] for each box + my $boxPos = $$dirInfo{BoxPos}; # hash of [position,length,irefVer(iref only)] for box in $outfile my $raf = $$et{RAF}; my $items = $$et{ItemInfo}; - my (%did, @mdatEdit, $name); + my (%did, @mdatEdit, $name, $tmap); return () unless $items and $raf; # extract information from EXIF/XMP metadata items my $primary = $$et{PrimaryItem}; my $curPos = $raf->Tell(); + my $lastID = 0; my $id; foreach $id (sort { $a <=> $b } keys %$items) { + $lastID = $id; $primary = $id unless defined $primary; # assume primary is lowest-number item if pitm missing my $item = $$items{$id}; # only edit primary EXIF/XMP metadata next unless $$item{RefersTo} and $$item{RefersTo}{$primary}; my $type = $$item{ContentType} || $$item{Type} || next; + $tmap = $id if $type eq 'tmap'; # save ID of primary 'tmap' item (tone-mapped image) # get ExifTool name for this item $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP' }->{$type}; next unless $name; # only care about EXIF and XMP @@ -700,8 +703,10 @@ ($$$) $type = "Exif\0"; $mime = ''; } - my $id = 1; - ++$id while $$items{$id} or $usedID{$id}; # find next unused item ID + my $id = ++$lastID; # use next highest available ID (so ID's in iinf are in order) + #[retracted] # create new item information hash to save infe box in case we need it for sorting + #[retracted] my $item = $$items{$id} = { }; + # add new infe entry to iinf box my $n = length($type) + length($mime) + length($enc) + 16; if ($id < 0x10000) { $add{iinf} .= pack('Na4CCCCnn', $n, 'infe', 2, 0, 0, 1, $id, 0) . $type . $mime . $enc; @@ -709,11 +714,14 @@ ($$$) $n += 2; $add{iinf} .= pack('Na4CCCCNn', $n, 'infe', 3, 0, 0, 1, $id, 0) . $type . $mime . $enc; } - # add new cdsc to iref + #[retracted] $add{iinf} .= $$item{infe}; + # add new cdsc to iref (also refer to primary 'tmap' if it exists) if ($irefVer) { - $add{iref} .= pack('Na4NnN', 18, 'cdsc', $id, 1, $primary); + my ($fmt, $siz, $num) = defined $tmap ? ('N', 22, 2) : ('', 18, 1); + $add{iref} .= pack('Na4NnN'.$fmt, $siz, 'cdsc', $id, $num, $primary, $tmap); } else { - $add{iref} .= pack('Na4nnn', 14, 'cdsc', $id, 1, $primary); + my ($fmt, $siz, $num) = defined $tmap ? ('n', 16, 2) : ('', 14, 1); + $add{iref} .= pack('Na4nnn'.$fmt, $siz, 'cdsc', $id, $num, $primary, $tmap); } # add new entry to iloc table (see ISO14496-12:2015 pg.79) my $ilocVer = Get8u($outfile, $$boxPos{iloc}[0] + 8); @@ -778,8 +786,9 @@ ($$$) my $added = 0; my $tag; foreach $tag (sort { $$boxPos{$a}[0] <=> $$boxPos{$b}[0] } keys %$boxPos) { + $$boxPos{$tag}[0] += $added; next unless $add{$tag}; - my $pos = $$boxPos{$tag}[0] + $added; + my $pos = $$boxPos{$tag}[0]; unless ($$boxPos{$tag}[1]) { $tag eq 'iref' or $et->Error('Internal error adding iref box'), last; # create new iref box @@ -826,9 +835,34 @@ ($$$) } # add new entries to this box (or add pitm after hdlr) substr($$outfile, $pos + $$boxPos{$tag}[1], 0) = $add{$tag}; + $$boxPos{$tag}[1] += length $add{$tag}; $added += length $add{$tag}; # positions are shifted by length of new entries } } + #[This sorting idea was retracted because just sorting 'iinf' wasn't sufficient to + # repair the problem where an out-of-order ID was added -- Apple Preview still + # ignores the gain-map image. It looks like either or both 'iref' and 'iloc' must + # also be sorted by ID, although the spec doesn't mention this] + #[retracted] # sort infe entries in iinf box if necessary + #[retracted] if ($$et{ItemsNotSorted}) { + #[retracted] if ($$boxPos{iinf}) { + #[retracted] my $iinfVer = Get8u($outfile, $$boxPos{iinf}[0] + 8); + #[retracted] my $off = $iinfVer == 0 ? 14 : 16; # offset to first infe item + #[retracted] my $sorted = ''; # sorted iinf payload + #[retracted] $sorted .= $$items{$_}{infe} || '' foreach sort { $a <=> $b } keys %$items; + #[retracted] if (length $sorted == $$boxPos{iinf}[1]-$off) { + #[retracted] # replace with sorted infe entries + #[retracted] substr($$outfile, $$boxPos{iinf}[0] + $off, length $sorted) = $sorted; + #[retracted] $et->Warn('Item info entries are out of order. Fixed.'); + #[retracted] ++$$et{CHANGED}; + #[retracted] } else { + #[retracted] $et->Warn('Error sorting item info entries'); + #[retracted] } + #[retracted] } else { + #[retracted] $et->Warn('Item info entries are out of order'); + #[retracted] } + #[retracted] delete $$et{ItemsNotSorted}; + #[retracted] } delete $$et{ItemInfo}; return @mdatEdit ? \@mdatEdit : undef; } @@ -1129,7 +1163,7 @@ ($$$) next; } } - undef $tagInfo if $tagInfo and $$tagInfo{Unknown}; + undef $tagInfo if $tagInfo and $$tagInfo{AddedUnknown}; if ($tagInfo and (not defined $$tagInfo{Writable} or $$tagInfo{Writable})) { my $subdir = $$tagInfo{SubDirectory}; diff --git a/bin/lib/Image/ExifTool/Writer.pl b/bin/lib/Image/ExifTool/Writer.pl index b4d6401..391c69a 100644 --- a/bin/lib/Image/ExifTool/Writer.pl +++ b/bin/lib/Image/ExifTool/Writer.pl @@ -4993,7 +4993,7 @@ (;$$) sub InverseDateTime($$;$$) { my ($self, $val, $tzFlag, $dateOnly) = @_; - my ($rtnVal, $tz); + my ($rtnVal, $tz, $fs); my $fmt = $$self{OPTIONS}{DateFormat}; # strip off timezone first if it exists if (not $fmt and $val =~ s/([-+])(\d{1,2}):?(\d{2})\s*(DST)?$//i) { @@ -5019,8 +5019,17 @@ ($$;$$) $strptimeLib = ''; } } - # handle factional seconds (%f), but only at the end of the string - my $fs = ($fmt =~ s/%f$// and $val =~ s/(\.\d+)\s*$//) ? $1 : ''; + # handle fractional seconds (%f) and time zone (%z) + ($fs, $tz) = ('', ''); + if ($fmt =~ /%(f|:?z)/) { + if ($fmt =~ s/(.*[^%])%f/$1/) { + $fs = $2 if $val =~ s/(.*)(\.\d+)/$1/; # (take last .### as fractional seconds) + } + if ($fmt =~ s/(.*[^%])%(:?)z/$1/) { + my $colon = $2; + $tz = "$2:$3" if $val =~ s/(.*)([-+]\d{2})$colon(\d{2})/$1/; + } + } my ($lib, $wrn, @a); TryLib: for ($lib=$strptimeLib; ; $lib='') { # handle %s format ourself (not supported in Fedora, see forum15032) @@ -5065,7 +5074,7 @@ ($$;$$) $a[$i] = "0$a[$i]"; # pad to 2 digits if necessary } } - $val = join(':', @a[5,4,3]) . ' ' . join(':', @a[2,1,0]) . $fs; + $val = join(':', @a[5,4,3]) . ' ' . join(':', @a[2,1,0]) . $fs . $tz; last; } } @@ -5077,7 +5086,9 @@ ($$;$$) my $ss = $a[4]; # get SS push @a, '00' while @a < 5; # add MM, SS if not given # get sub-seconds if they exist (must be after SS, and have leading ".") - my $fs = (@a > 5 and $val =~ /(\.\d+)\s*$/) ? $1 : ''; + unless ($fmt) { + $fs = (@a > 5 and $val =~ /(\.\d+)\s*$/) ? $1 : ''; + } # add/remove timezone if necessary if ($tzFlag) { if (not $tz) { diff --git a/bin/perl-Image-ExifTool.spec b/bin/perl-Image-ExifTool.spec index 1bf78f5..663906d 100644 --- a/bin/perl-Image-ExifTool.spec +++ b/bin/perl-Image-ExifTool.spec @@ -1,6 +1,6 @@ Summary: perl module for image data extraction Name: perl-Image-ExifTool -Version: 13.08 +Version: 13.10 Release: 1 License: Artistic/GPL Group: Development/Libraries/Perl diff --git a/lib/exiftool_vendored/version.rb b/lib/exiftool_vendored/version.rb index a2219fc..2916e68 100644 --- a/lib/exiftool_vendored/version.rb +++ b/lib/exiftool_vendored/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ExiftoolVendored - VERSION = Gem::Version.new('13.08.0') + VERSION = Gem::Version.new('13.10.0') end